• 打造跨平台.NET Core后台服务


    ASP.NET Core使用TopShelf部署Windows服务

    asp.net core很大的方便了跨平台的开发者,linux的开发者可以使用apache和nginx来做反向代理,windows上可以用IIS进行反向代理。
    反向代理可以提供很多特性,固然很好。但是还有复杂性,我们也可以使用windows service来直接启动kestrel。

    asp.net core官方网站提供了一种基于windows服务部署的方法:在 Windows 服务中托管 ASP.NET Core
    这种方式需要修改代码,然后部署的时候,使用命令行创建、安装服务,然后再启动。

    感觉还是不够爽快,我们可以使用topshelf改造一下。

    TopShelf

    topshelf可以很便捷地将一个windows console程序改造成windows service,只需要稍微修改一下代码结构,然后通过nuget包就可以简单操作了。安装与部署也是极其方便,而且,topshelf在调试的时候,直接是作为console程序,极其便于调试。

    TopShelf项目地址:http://topshelf-project.com/

    步骤

    首先引用nuget包:

    Copy
    Install-Package TopShelf
    

    然后改造一下program.cs

    Copy
    public class Program
    {
        public static void Main(string[] args)
        {
            var rc = HostFactory.Run(x =>                                   //1
            {
                x.Service<MainService>(s =>                                   //2
                {
                    s.ConstructUsing(name => new MainService(args));                //3
                    s.WhenStarted(tc => tc.Start());                         //4
                    s.WhenStopped(tc => tc.Stop());                          //5
                });
                x.RunAsLocalSystem();                                       //6
    
                x.SetDescription("JwtAPIService");                   //7
                x.SetDisplayName("JwtAPIService");                                  //8
                x.SetServiceName("JwtAPIService");                                  //9
            });                                                             //10
    
            var exitCode = (int)Convert.ChangeType(rc, rc.GetTypeCode());  //11
            Environment.ExitCode = exitCode;
    
            //CreateWebHostBuilder(args).Build().RunAsService();
        }
    }
    

    这里指定服务程序的内容在MainService这个类里面,并通过代码指定了服务的名称和描述等行为。以前的启动CreateWebHostBuilder方法转移到了这个类中:

    Copy
    public class MainService
    {
        private string[] args;
        public MainService(string[] vs)
        {
            args = vs;
        }
        public void Start()
        {
            var isService = !(Debugger.IsAttached || args.Contains("--console"));
            var builder = CreateWebHostBuilder(args.Where(arg => arg != "--console").ToArray());
    
            if (isService)
            {
                var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
                var pathToContentRoot = Path.GetDirectoryName(pathToExe);
                builder.UseContentRoot(pathToContentRoot);
            }
    
            var host = builder.Build();
            host.Run();
        }
    
        public void Stop()
        {
        }
    
        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
        {
            var config = new ConfigurationBuilder()
    // .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("config.json", optional: true, reloadOnChange: true)
    .Build();
    
            return WebHost.CreateDefaultBuilder(args)
                    .UseKestrel()
                    .UseConfiguration(config)
                    .UseStartup<Startup>();
        }
    }
    
    • Start方法指定服务启动时,服务的执行不需要依赖于Microsoft.AspNetCore.Hosting.WindowsServices这个nuget包。
    • 另外Contentroot需要注意,使用windows服务进行提供服务,GetCurrentDirectory的根目录是system32,而不是asp.net core的dll的目录。使用appsettings.json时,可能会引起问题,最好使用自定义的程序配置(例如这里通过config.json进行设置)。
    • 注意和调试的时候不同,launchsettings.json在正式运行的时候是不可用的,请通过编码(比如UseUrls)来设置监听端口。

    运行

    • 确定是否存在 Windows 运行时标识符 (RID),或将其添加到包含目标框架的 中:
    Copy
    <PropertyGroup>
       <TargetFramework>netcoreapp2.1</TargetFramework>
       <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
    </PropertyGroup>
    
    • 发布,最终可以得到可执行程序。直接双击运行,程序就可以以console的形式启动,方便调试。
    • 命令行运行xxxx.exe install就而可以安装服务,然后服务就可以自动启动。
    • 命令行运行xxxx.exe uninstall就可以卸载服务。整个过程不需要新建用户与策略。

    后记

    吐槽:直接使用TopShelf,调试windows服务的过程变得不那么痛苦了,想起附加调试器的过程,简直了。
    P.S. 需要最新版本的topshelf才可以支持asp.net core的服务部署。

    出处:https://www.cnblogs.com/podolski/p/10054286.html

    =======================================================================================

    打造跨平台.NET Core后台服务

    续之前讲的在 TopShelf上部署ASP.NET Core程序,作为后台服务运行,自从.NET Core 3.0出现以后,出现了自带的Generic Host,使得自托管服务变为可能。这种方式和TopShelf方式一样,可以直接F5进行服务的调试,也为跨平台后台服务编写提供了一种新的方案。

    创建服务#

    以VS2019为例,确保安装了.NET CORE 3.0以上的SDK,新建项目,在项目模板里面可以找到Worker Service模板,创建后,vs已经帮我们创建了Program.cs和Worker.cs两个文件。

    在Program.cs中,

    Copy
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Threading.Tasks;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    
    namespace WorkerServiceTest
    {
        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
    		    Host.CreateDefaultBuilder(args)
    		    .ConfigureServices((hostContext, services) =>
    		    {
    		        services.AddHostedService<Worker>();
    		    });
            }
        }
    }
    

    可以发现,配置的方式和ASP.NET CORE的方式基本一样一样的,使用了内置的DI容器。那我们同样可以使用AddSingleton等方法进行其他逻辑的注入,也可以添加多个服务任务。

    而Worker类已经写了好一个范例,其中有一个ExecuteAsync方法,可以直接执行后台任务。这个时候,直接F5就可以正常运行了,自带了一个显示当前时间的小程序。

    跨平台支持#

    虽然程序可以正常执行,但是还不能正常部署为服务,需要依据平台添加对应的nuget包:

    • windows服务,需要添加:
    Copy
    Install-Package Microsoft.Extensions.Hosting.WindowsServices
    
    • Linux服务,需要添加:
    Copy
    Install-Package Microsoft.Extensions.Hosting.Systemd
    

    如果想实现一套程序多处运行,那么直接同时安装两个package就可以了。接下来在CreateHostBuilder中,添加UseWindowsService()和UseSystemd()。

    Copy
    public static IHostBuilder CreateHostBuilder(string[] args)
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            return Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                }).UseWindowsService();
        }
        else
        {
            return Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) =>
                {
                    services.AddHostedService<Worker>();
                }).UseSystemd();
        }
    }
    

    这里使用到了.NET Core判断平台的一个函数:IsOSPlatform,可以判断是否在Windows平台运行,并进行分别调用。

    部署#

    编译完成之后,找到生成的exe文件路径。

    Windows下部署#

    管理员下运行cmd/powershell,执行

    Copy
    sc.exe create WorkerServiceTest binPath=C:Userssource
    eposWorkerServiceTestWorkerServiceTestinDebug
    etcoreapp3.1WorkerServiceTest.exe
    

    提示CreateService 成功即安装成功了,可以输入下面的命令运行服务。

    Copy
    sc.exe start WorkerServiceTest
    

    sc.exe负责管理服务,具体配置启动方式和删除,可以查看命令的帮助。另外,友情提醒,如果是在powershell中,不要省略这个.exe,sc有别的用处...

    Linux下部署#

    将整个程序文件夹传输到Linux文件夹下,我这边使用的是CentOS 8。新建一个运行服务的用户:

    Copy
    useradd -m dotnetuser -p dotnetpass
    

    转到/etc/systemd/system文件夹,建立一个WorkerServiceTest.service的文件,这个WorkerServiceTest是你的服务名称。

    输入以下内容并保存(systemd配置文件):

    Copy
    [Unit]
    Description=WorkerServiceTest
    
    [Service]
    ExecStart=dotnet /bin/dotnet/WorkerServiceTest.dll
    WorkingDirectory=/bin/dotnet/
    User=dotnetuser
    Group=dotnetuser
    Restart=on-failure
    SyslogIdentifier=WorkerServiceTest
    PrivateTmp=true
    
    [Install]
    WantedBy=multi-user.target
    

    注意,你需要已经安装有dotnet runtime 3.0以上版本才可以。
    可以使用以下命令进行安装

    Copy
    yum install dotnet-runtime-3.1
    

    接下来是配置服务和启动服务

    Copy
    #重载配置
    systemctl daemon-reload
    #设置服务自动启动
    systemctl enable WorkerServiceTest.service 
    #运行服务
    systemctl start WorkerServiceTest.service
    #查询服务状态
    systemctl status WorkerServiceTest.service
    

    然后可以发现,程序可以正常运行。
    img

    补充#

    作为服务,应该要提供一些状态用于外部监测,在Worker.cs中,Worker类可以重写StartAsyncStopAsync方法,提供服务启动和停止的信息,但是windows提供的服务失败后动作等功能都找不到配置的地方,可能这就是局限吧。

    总结#

    一次编写,处处运行,对于后台服务也是如此,很简洁。但是暂时手上没有mac电脑,也不知道mac上面有没有对应的解决方案。可能TopShelf的mono模式可以支持吧。

    比较TopShelf模式#

    总体讲,相较于TopShelf的方式,Service Worker方式各有利弊。

    优点:

    1. 在相同的框架(.NET CORE 3.0+)下支持跨平台,支持linux服务的systemctl管理,topshelf在linux下需要mono。
    2. 配置方式和ASP.NET CORE相似度极高,基本上可以无缝切换。

    缺点:

    1. 不支持TopSelf的自带命令install/start/uninstall等命令,依然需要sc进行部署,比较麻烦。
    2. 不支持windows的很多服务管理特性(比如Pause,依赖管理)。
    3. 只支持.NET CORE 3.0以后的框架,不支持.NET FRAMEWORK和早期版本的.NET CORE。

    参考资料#

    出处:https://www.cnblogs.com/podolski/p/13890572.html

  • 相关阅读:
    Codeforces 754A Lesha and array splitting (搜索)
    浅入分析Linux
    MakeFile基本使用
    Mac 安装YCM
    Homebrew 配置
    虚拟机复制操作CentOS6导致eth0转为eth0以至于网络服务启动失败的解决方案
    Kickstart安装
    Linux编译安装MySQL
    Python源码读后小结
    编译原理小结
  • 原文地址:https://www.cnblogs.com/mq0036/p/14147850.html
Copyright © 2020-2023  润新知