本篇我们以一个Sample工程,来说明如何把一个常见结构的desktop application,转制成APPX并在MS Store提供下载。

之前的篇章中,我们已经介绍了一些内容,包括如何通过Visual Studio创建Packaging工程, 如何将Class Libraries转换到.NET Standard版本。至此,UI界面,以及部分DLL的迁移问题得到解决。但有时候我们的desktop application还包括一个本地的Background Service。那么目前微软推荐的策略,依然是通过创建一个WCF服务,然后host在Windows Service上,来提供给前端的APPX访问。

可能有同学要问,为什么我们需要Windows Service。这是因为在前台程序中,一般不会要求admin权限,这在企业级软件中是较为常见的需求,用PowerPiont的普通员工,通常被认为即没有power也没有point,更不需要admin权限……(悲剧啊T_T)但我们可以把需要admin权限,访问硬件等相关操作,放到Service中,由IT统一部署到机器上,避免了没有admin权限无法正常运行程序的问题。

在接下来的Sample中,我们试图通过代码启动一个Windows服务"aspnet_state"。这个工程非常的简单,我们要做的仅仅是在UWP project中调用一下Windonws Service上运行的WCF服务。工程结构如下图。因为工程主要想说明UI程序对WCF服务的引用,所以请不要在意使用UI程序是UWP还是WPF。实际使用中,对于Desktop Bridge的程序,非WCF的其他Background Service也是可以的,比如Named Pipes等。

我们的UI部分非常的简单,仅是在MainPage.cs中调用WCF服务中提供的方法,这里我们可以看到传递了一个string类型的参数作为要启动的service name。

    public sealed partial class MainPage : Page
{
private string serviceName = "aspnet_state";
private LocalServiceClient client = new LocalServiceClient(); public MainPage()
{
this.InitializeComponent();
} private async void Button_Click(object sender, RoutedEventArgs e)
{
var status = await client.StartServiceAsync(serviceName);
textBlockStatus.Text = status.ToString();
}
}

如何编写WCF服务这里就不赘述了,有兴趣的同学可以去MSDN上学习:
https://docs.microsoft.com/en-us/dotnet/framework/wcf/index
同样直接给出如何将WCF服务host在Windows Service上的链接:
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-host-a-wcf-service-in-a-managed-windows-service
在WCF service的代码里,我们通过ServiceController启动另一个系统的Windows Service,需要注意的是,我们测试用的"aspnet_state"默认是未开启的,而启动Windows Service要求程序具有admin权限。

    public class LocalServiceWrapper : ILocalService
{
public ServiceControllerStatus StartService(string name)
{
ServiceController controller = new ServiceController(name); if (controller.Status == ServiceControllerStatus.Stopped)
{
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds());
}
return controller.Status;
}
}

你也可以试试Bluetooth Support Service,Service name是"bthserv"。通过程序开启蓝牙服务似乎更合理,但反复测试disable/enable蓝牙让我很烦躁。所以最终我换成了"aspnet_state"。
把程序拆分成UI和WCF Service两部分的目的,是将需要admin权限等不符合MS Store审核要求的代码,从APPX中移出,已servcie的形式来调用。最终的结构图可以分为两种。
第一种是采用Desktop Bridge的形式,APPX部分可以继续包含native C++ libraries,也可以调用任何形式的background service。唯一的问题是,在提交APPX到商店审核的时候,需要申请相应权限。企业级的软件通过审核的可能性很大,个人作品就不清楚了。审核通过后APPX获得微软的签名。此时用户可从商店下载APPX,然后手动安装Service部分。也可以由公司IT以Sideload的方式统一安装APPX+Service。

第二种更为纯粹,由UWP+.NET Standard+WCF组成,相应也需要更多的改动,而Native C++ Libraries的部分则需要下沉到Service中。这种的好处在于迁移的更为彻底,对未来有着更好的适应。当然哪天某软翻脸不认账,抛弃UWP又回头去搞.NET Core的WPF的话,你就当我没说过……

本篇讨论了如何将现有的desktop application,在维持已有架构的前提下,转制成APPX放到MS Store提供下载。
当然你们会觉得多出来的Service部分简直不能忍。后续我会进一步介绍如何处理Service部分,不至于让强迫症患者在评论里骂我……
本篇Sample工程的GitHub链接:
https://github.com/manupstairs/UWPWithWCFSample

最新文章

  1. simpleCart的简单使用及配置
  2. 关于url中的#-----hash
  3. VisualStudio2013+EF6+MySql5.5环境下配置
  4. AIM Tech Round 3 (Div. 2) A
  5. Linux 修改hostname 文件
  6. CSS和JavaScript以及Ajax实现预加载图片的方法及优缺点分析
  7. lightoj 1010
  8. 在xcode6.1和ios10.10.1环境下实现app发布
  9. iOS开发: 向右滑动手势功能实现
  10. java 学习笔记之 流、文件的操作
  11. 讲讲网络模块中加解密那点儿事--AES+BASE64
  12. LOJ# 572. 「LibreOJ Round #11」Misaka Network 与求和(min25筛,杜教筛,莫比乌斯反演)
  13. angular.module()参数问题
  14. 7、Redis中对ZSet类型的操作命令
  15. JAVA的String类的常用方法(转载)
  16. Linux ip命令详解
  17. Winfom 插件式(Plugins)/模块化开发框架-动态加载DLL窗体-Devexpress
  18. sql用法
  19. Hibernate入门(三)—— 一对多、多对多关系
  20. JVM(二) 对象存活判断和垃圾回收算法

热门文章

  1. Win 10 关闭了.net framework 3.5后再开启不成功
  2. eclipse构建maven的web项目(转载)
  3. springMVC学习一 工作机制
  4. 48.UIButton上的字体居右对齐
  5. 使用Hadoop API 解压缩 HDFS文件
  6. 2018.06.27"Shortest" pair of paths(费用流)
  7. PLSQL Developer对oracle中的数据进行备份恢复
  8. application.properties /application.yml官网查看配置;springboot application.properties 官网查看,info yml 查看;springboot.yml查看info;springboot.yml查看Actuator监控中心info
  9. IntelliJ IDEA 2017版 Spring5 java.lang.NoSuchMethodError: org.springframework.boot.SpringApplication.<init>([Ljava/lang/Object;)V
  10. ng-show和ng-if的区别和使用场景