• 迁移桌面程序到MS Store(7)——APPX + Service


    本篇我们以一个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(5));
                }
                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

  • 相关阅读:
    使用keepalived实现双机热备
    MYSQL ERROR CODE 错误编号的意义
    Mysql slow query log
    eclipse svn 分支合并到主干
    Timer的schedule和scheduleAtFixedRate方法的区别解析
    Java内部类引用外部类中的局部变量为何必须是final问题解析
    nginx中有关命令和日志切割,配置文件加载的详细阐述
    流媒体中ffmpeg 命令的使用
    windows下搭建nginx服务器及实现nginx支持https配置流程
    mysql 中sql语句的执行顺序
  • 原文地址:https://www.cnblogs.com/manupstairs/p/10636732.html
Copyright © 2020-2023  润新知