加入收藏 | 设为首页 | 会员中心 | 我要投稿 莱芜站长网 (https://www.0634zz.com/)- 云连接、建站、智能边缘云、设备管理、大数据!
当前位置: 首页 > 编程开发 > asp.Net > 正文

谈谈.NET Core中基于Generic Host来实现后台任务

发布时间:2020-07-09 04:26:56 所属栏目:asp.Net 来源:互联网
导读:目录前言什么是Generic Host后台任务示例控制台形式消费MQ消息的后台任务Web形式部署IHostedService和BackgroundService的区别IHostBuilder的扩展写法总结前言很多时候,后台任务对我们来说是一个利器,帮我们在后面处理了成千上万的事情。在.NET Framework时

<div class="toc">
<p class="toc-title">目录


<div class="toc-list">

很多时候,后台任务对我们来说是一个利器,帮我们在后面处理了成千上万的事情。

在.NET Framework时代,我们可能比较多的就是一个项目,会有一到多个对应的Windows服务,这些Windows服务就可以当作是我们所说的后台任务了。

我喜欢将后台任务分为两大类,一类是不停的跑,好比MQ的消费者,RPC的服务端。另一类是定时的跑,好比定时任务。

那么在.NET Core时代是不是有一些不同的解决方案呢?答案是肯定的。

Generic Host就是其中一种方案,也是本文的主角。

Generic Host是ASP.NET Core 2.1中的新增功能,它的目的是将HTTP管道从Web Host的API中分离出来,从而启用更多的Host方案。

这样可以让基于Generic Host的一些特性延用一些基础的功能。如:如配置、依赖关系注入和日志等。

Generic Host更倾向于通用性,换句话就是说,我们即可以在Web项目中使用,也可以在非Web项目中使用!

虽然有时候后台任务混杂在Web项目中并不是一个太好的选择,但也并不失是一个解决方案。尤其是在资源并不充足的时候。

比较好的做法还是让其独立出来,让它的职责更加单一。

下面就先来看看如何创建后台任务吧。

我们先来写两个后台任务(一个一直跑,一个定时跑),体验一下这些后台任务要怎么上手,同样也是我们后面要使用到的。

这两个任务统一继承BackgroundService这个抽象类,而不是IHostedService这个接口。后面会说到两者的区别。

  1. 一直跑的后台任务

先上代码

public class PrinterHostedService2 : BackgroundService
{
    private readonly ILogger _logger;
    private readonly AppSettings _settings;
public PrinterHostedService2(ILoggerFactory loggerFactory,IOptionsSnapshot<AppSettings> options)
{
    this._logger = loggerFactory.CreateLogger<PrinterHostedService2>();
    this._settings = options.Value;
}

public override Task StopAsync(CancellationToken cancellationToken)
{
    _logger.LogInformation("Printer2 is stopped");
    return Task.CompletedTask;
}

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        _logger.LogInformation($"Printer2 is working. {_settings.PrinterDelaySecond}");
        await Task.Delay(TimeSpan.FromSeconds(_settings.PrinterDelaySecond),stoppingToken);
    }
}

}

来看看里面的细节。

我们的这个服务继承了BackgroundService,就一定要实现里面的ExecuteAsync,至于StartAsync和StopAsync等方法可以选择性的override。

我们ExecuteAsync在里面就是输出了一下日志,然后休眠在配置文件中指定的秒数。

这个任务可以说是最简单的例子了,其中还用到了依赖注入,如果想在任务中注入数据仓储之类的,应该就不需要再多说了。

同样的方式再写一个定时的。

  1. 定时跑的后台任务

这里借助了Timer来完成定时跑的功能,同样的还可以结合Quartz来完成。

public class TimerHostedService : BackgroundService
{
    //other ...
private Timer _timer;

protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
    _timer = new Timer(DoWork,null,TimeSpan.Zero,TimeSpan.FromSeconds(_settings.TimerPeriod));
    return Task.CompletedTask;
}

private void DoWork(object state)
{
    _logger.LogInformation("Timer is working");
}

public override Task StopAsync(CancellationToken cancellationToken)
{
    _logger.LogInformation("Timer is stopping");
    _timer?.Change(Timeout.Infinite,0);
    return base.StopAsync(cancellationToken);
}

public override void Dispose()
{
    _timer?.Dispose();
    base.Dispose();
}

}

和第一个后台任务相比,没有太大的差异。

下面我们先来看看如何用控制台的形式来启动这两个任务。

这里会同时引入NLog来记录任务跑的日志,方便我们观察。

Main函数的代码如下:

class Program
{
    static async Task Main(string[] args)
    {
        var builder = new HostBuilder()
            //logging
            .ConfigureLogging(factory =>
            {
                //use nlog
                factory.AddNLog(new NLogProviderOptions { CaptureMessageTemplates = true,CaptureMessageProperties = true });
                NLog.LogManager.LoadConfiguration("nlog.config");
            })
            //host config
            .ConfigureHostConfiguration(config =>
            {
                //command line
                if (args != null)
                {
                    config.AddCommandLine(args);
                }
            })
            //app config
            .ConfigureAppConfiguration((hostContext,config) =>
            {
                var env = hostContext.HostingEnvironment;
                config.AddJsonFile("appsettings.json",optional: true,reloadOnChange: true)
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json",reloadOnChange: true);
            config.AddEnvironmentVariables();

            if (args != null)
            {
                config.AddCommandLine(args);
            }
        })
        //service
        .ConfigureServices((hostContext,services) =>
        {
            services.AddOptions();
            services.Configure<AppSettings>(hostContext.Configuration.GetSection("AppSettings"));

            //basic usage
            services.AddHostedService<PrinterHostedService2>();
            services.AddHostedService<TimerHostedService>();
        }) ;

    //console 
    await builder.RunConsoleAsync();

    ////start and wait for shutdown
    //var host = builder.Build();
    //using (host)
    //{
    //    await host.StartAsync();

    //    await host.WaitForShutdownAsync();
    /

(编辑:莱芜站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读