基于 .NET CORE 3.1 提供的 worker service 来创建 windows 服务

.NET CORE 3.1 提供了 worker service 这么一个模板,可以方便开发者来创建”windows 服务程序“(同样可发布于 linux)。本篇以 centos 7.6 为发布环境,简要说明如何使用 worker service 来创建服务,并部署发布到 centos 中。

你可以通过以下命令来查看本地安装的 .net core 环境:

dotnet   --version  # 笔者为 3.1.301

你可以通过以下命令来查看是否含有 worker service 模板:

dotnet  new  -l

安装

方式1:命令行形式安装

你可以通过如下命令在当前解决方案中安装:

这里以项目:”OrderCenter.ConsumerService“ 为例

cd  解决方案路径

dotnet  new  worker  -o  OrderCenter.ConsumerService

# 之后你可以手动在 解决方案 中添加刚创建的项目,或者通过以下命令来进行引用
dotnet  sln  OrderCenter.sln  add   ./OrderCenter.ConsumerService.csproj

创建的项目如下:

方式2:UI界面

如果你不习惯使用命令行来创建项目,可以直接通过 UI 界面来添加项目:

  • 注:笔者的VS版本为 Visual Studio 2019 - v16.6.2

配置

worker service 默认支持 IOC,你可以直接使用,同时你也可以直接配置日志等信息,示例如下:

本博文涉及的引用包及版本如下:

你可以在 Program.cs 中进行配置,代码如下:

public static IHostBuilder CreateHostBuilder(string[] args) =>
   Host.CreateDefaultBuilder(args)
       .UseContentRoot(Directory.GetCurrentDirectory())
       .ConfigureAppConfiguration((hostingContext, config) =>
           {
               config
                   .AddJsonFile("appsettings.json", true, true)
                   .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")}.json", true, true)
                   .AddCommandLine(args);
           })
       .ConfigureLogging(config =>
       {
           config.SetMinimumLevel(LogLevel.Trace);
           if (Environment.OSVersion.Platform == PlatformID.Unix)
           {
               config.AddLog4Net("log4net.linux.config");
           }
           else
           {
               config.AddLog4Net();
           }
       })
       .ConfigureServices((hostContext, services) =>
       {
           #region >> 服务发现
          // 你的业务代码,若有
           #endregion

           #region >> 初始化数据库
           // 你的业务代码,若有
           #endregion

           #region >> IOC
           services.AddApplicationService();
           services.AddDomainService();
           services.AddRepository();
           #endregion

           services.AddHostedService<Worker>();
       }).UseSystemd(); //需引用 Microsoft.Extensions.Hosting.Systemd.dll

你可以在 Worker.cs 中编写业务代码,示例如下:

本文以 MQ 消费者为例:

public class Worker : BackgroundService
{
    private readonly IRabbitMqDomainService _mqClient;

    public Worker(IRabbitMqDomainService mqClient) //支持 IoC
    {
        _mqClient = mqClient;
        _mqClient.Initialize();
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _mqClient.SubscribeAutoAuditOrder();
        _mqClient.SubscribeGenerateDeliverSheet();
        while (!stoppingToken.IsCancellationRequested)
        {
            LogHelper<Worker>.LogInformation("服务还活着。", "ExecuteAsync");
           //对于 定时任务,如果要求不高,可直接使用 worker service 自带的特性来进行。
           await Task.Delay(600000, stoppingToken);
        }
    }

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        LogHelper<Worker>.LogInformation("服务停止。", "StopAsync");
        return base.StopAsync(cancellationToken);
    }
}

生成发布文件

通过命令生成

通过以下命令可以生成发布文件,

cd 发布项目路径
# 生成发布到 linux 环境的发布包
dotnet  publish  -c  release  -r  linux-x64  -f  netcoreapp3.1

# 生成发布到  windows 环境的发布包
dotnet  publish  -c  release  -r  win81-x64  -f  netcoreapp3.1

通过 UI 生成

发布

发布到 linux 中

将对应的发布文件上传到服务器中

假设上传到的目录为:

/usr/bp/myservice/

假设服务的运行程序为:/usr/bp/myservice/OrderCenter.ConsumerService.dll

自启动设置

这里介绍 3 种让服务开机自启动的方式,当然你也可以用 PM2 之类的进程守护程序来进行。

1.通过 crontab 来设置开机运行

crontab  -e

#在编辑器中添加如下代码:
@reboot  /usr/bp/myservice/OrderCenter.ConsumerService.dll

2.通过在 rc.local 文件夹设置开机运行

vi   /etc/rc.d/rc.local

# 在该文件中添加如下命令即可
/usr/bp/myservice/OrderCenter.ConsumerService.dll

3.通过 systemd 进行开机启动

创建 service 文件

cd  /etc/systemd/systerm/
vim  myservice.service

# 创建的文件内容如下---请自行根据项修改对应的值
[Unit]
Description=work service demo

[Service]
# Case sensitive.  目录
WorkingDirectory=/usr/bp/myservice
# 具体文件
ExecStart=/bin/dotnet /usr/bp/myservice/OrderCenter.ConsumerService.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=your-service-name
User=root
Environment=ASPNETCORE_ENVIRONMENT=Development
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

设置自启动

systemctl  enable  myservice

启动服务

systemctl  start  myservice

发布到 windows 环境中

如果要发布到 windows 服务种,则需要安装 Microsoft.Extensions.Hosting.WindowsServices.dll (替换上面的 Microsoft.Extensions.Hosting.Systemd)

同时修改 Program.cs 代码

public static IHostBuilder CreateHostBuilder(string[] args) =>
   Host.CreateDefaultBuilder(args)
       .UseContentRoot(Directory.GetCurrentDirectory())
       .ConfigureAppConfiguration((hostingContext, config) =>
           {
               config
                   .AddJsonFile("appsettings.json", true, true)
                   .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT")}.json", true, true)
                   .AddCommandLine(args);
           })
       .ConfigureLogging(config =>
       {
           //other codes                    
           services.AddHostedService<Worker>();
       }).UseWindowsService(); //替换原 UseSystemd()

通过 sc.exe 命令行工具来创建服务,命令如下:

# 创建服务
# 注意:binPath后面的 "="号后面有一个空格
sc.exe create YOURSERVICENAME binPath= X:\OrderCenter.ConsumerService.exe

# 启动服务
sc.exe  start  YOURSERVICENAME

# 查询服务
sc.exe  query  YOURSERVICENAME

# 停止服务
sc.exe stop YOURSERVICENAME 

# 删除服务
sc.exe delete YOURSERVICENAME

参考: