介绍

asp.net core 3增加了一个非常有意思的功能worker service.他是一个asp.net core模板,他允许我们创建托管长期的运行的后台服务,这些服务具体实现ihostedservice接口的后台任务逻辑,他被成为”托管服务”.同时他们可以部署到windows中windows服务,以及linux守护程序.

创建一个托管服务

我们通过命令行界面中的dotnet new 命令。通过如下代码创建一个名为customworker的workerservice的应用。

dotnet new worker -o customworker

program.cs:

using system;
using system.collections.generic;
using system.linq;
using system.threading.tasks;
using microsoft.extensions.dependencyinjection;
using microsoft.extensions.hosting;

namespace workerservicedemo
{
    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>();
                });
    }
}

worker:

backgroundservice是实现了ihostedservice的基类.调用 executeasync(cancellationtoken) 来运行后台服务。实现返回一个task,其表示后台服务整个生存期.在 exeuteasync(例如通过调用await)之前,不会启动任何其他服务.避免在executeasync中执行长时间的阻塞初始化. stopasync(cancellationtoekn) 中的主机块等待完成executeasync

调用 ihostedservice.stopasync 时,将触发取消令牌。 当激发取消令牌以便正常关闭服务时,executeasync 的实现应立即完成。 否则,服务将在关闭超时后不正常关闭。

using system;
using system.collections.generic;
using system.linq;
using system.threading;
using system.threading.tasks;
using microsoft.extensions.hosting;
using microsoft.extensions.logging;

namespace workerservicedemo
{
    public class worker : backgroundservice
    {
        private readonly ilogger<worker> _logger;

        public worker(ilogger<worker> logger)
        {
            _logger = logger;
        }

        public override async task startasync(cancellationtoken cancellationtoken)
        {
            await base.startasync(cancellationtoken);
        }

        public override async task stopasync(cancellationtoken cancellationtoken)
        {
            await base.stopasync(cancellationtoken);
        }

        protected override async task executeasync(cancellationtoken stoppingtoken)
        {
            while (!stoppingtoken.iscancellationrequested)
            {
                _logger.loginformation("worker running at: {time}", datetimeoffset.now);
                await task.delay(1000, stoppingtoken);
            }
        }

        public override void dispose()
        {
        }
    }
}

已使用addhostedservice扩展方法在 ihostbuilder.configureservices(program.cs)中注册该服务。

 services.addhostedservice<worker>();
 

workerservices部署到windows服务

安装 workerservices模板

在ihostbuilder使用usewindowsservice扩展方法

using microsoft.extensions.dependencyinjection;
using microsoft.extensions.hosting;


namespace workerservicedemo
{
    public class program
    {
        public static void main(string[] args)
        {
            createhostbuilder(args).build().run();
        }

        public static ihostbuilder createhostbuilder(string[] args)
        {
            return host.createdefaultbuilder(args)
               
                .configureservices((hostcontext, services) =>
                {
                    services.addhostedservice<worker>();
                }).usewindowsservice(); ;

        }
    }
}

现在我们可以部署我们的windows服务了。

发布方式

  • 使用sc.exe工具
  • 直接部署exe文件

发布windows服务

dotnet restore
dotnet publish

sc.exe部署

sc.exe create demoworker binpath= publish\xxxx.exe
sc.exe start workerservicesname

部署exe文件

workerservicesname.exe install
workerservicesname.exe start

使用sc.exe停止和删除

sc.exe stop workerservicesname 
sc.exe delete workerservicesname 

非sc.exe停止和删除

workerservicesname stop  
workerservicesname uninstall

在linux设置守护程序

添加microsoft.extensions.hosting.systemd nuget软件包

将usesystemd()添加上。

        public static ihostbuilder createhostbuilder(string[] args)
        {

            return host.createdefaultbuilder(args)
                .configureservices((hostcontext, services) =>
                {
                    services.addhostedservice<worker>();
                }).usesystemd();

        }

在linux上设置为守护程序。

reference

https://github.com/hueifeng/blogsample/tree/master/src/workerservicedemo