为了账号安全,请及时绑定邮箱和手机立即绑定

ASP.NET Core 2.2 基础知识(九) 使用托管服务实现后台任务

标签:
C#

在 ASP.NET Core 中,后台任务作为托管服务实现.托管服务是一个类,而且必须实现 IHostedService 接口,该接口定义了两个方法:

  • StartAsync(CancellationToken cancellationToken)  该方法包含启动后台任务的逻辑,当启动服务器并触发 IApplicationLifetime.ApplicationStarted 后调用该方法.

  • StopAsync(CancellationToken cancellationToken)主机正常关闭时触发,包含结束后台任务和处理任何非托管资源的逻辑.如果应用意外关闭,则可能不会调用.

托管服务在应用启动时激活一次,在应用关闭时正常关闭.实现 IDisposable 时,可在处置服务容器时处理资源.如果在执行后台任务期间引发错误,即使未调用 StopAsync ,也应调用 Dispose.

示例一:计时的后台任务

复制代码

    public class TimedHostedService : IHostedService, IDisposable
    {        private readonly ILogger _logger;        private Timer _timer;        public TimedHostedService(ILogger<TimedHostedService> logger)
        {
            _logger = logger;
        }        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Timed Background Service is starting." + DateTime.Now);
            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));//立即执行一次,每5秒执行一次
            return Task.CompletedTask;
        }        private void DoWork(object state)
        {
            _logger.LogInformation("Timed Background Service is working." + DateTime.Now);
        }        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("Timed Background Service is stopping." + DateTime.Now);
            _timer?.Change(Timeout.Infinite, 0);//不再执行
            return Task.CompletedTask;
        }        public void Dispose()
        {
            _timer?.Dispose();
        }
    }

复制代码

 

注册该后台任务:

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);            services.AddHostedService<TimedHostedService>();
        }

 

在控制台启动该项目,期间用 ctrl+C 结束应用.

其实官方帮我们封装了一个类来简化上述代码:

  /// <summary>
  /// Base class for implementing a long running <see cref="T:Microsoft.Extensions.Hosting.IHostedService" />.  /// </summary>
  public abstract class BackgroundService : IHostedService, IDisposable

 

因此上述代码可以修改成:

复制代码

    public class MyBackGroundTask : BackgroundService
    {        private readonly ILogger _logger;        private Timer _timer;        public MyBackGroundTask(ILogger<MyBackGroundTask> logger)
        {
            _logger = logger;
        }        
        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            _logger.LogInformation($" MyBackGroundTask is starting. {DateTime.Now}");            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation($" MyBackGroundTask is working. {DateTime.Now}");                await Task.Delay(5000, stoppingToken);
            }            _logger.LogInformation($" MyBackGroundTask is stopping. {DateTime.Now}");
        }
    }

复制代码

 

但是,我发现 

_logger.LogInformation($" MyBackGroundTask is stopping. {DateTime.Now}");

这句代码始终不执行.不知道是哪里没搞对.希望大神能帮个忙..

 

 示例二:在后台任务中使用有作用域的服务

要使用有作用域的服务,需要先创建一个作用域.默认情况下,不会为托管服务创建作用域.

 

复制代码

    public interface IScopedProcessingService
    {        void DoWork();
    }    public class ScopedProcessingService : IScopedProcessingService
    {        private readonly ILogger _logger;        public ScopedProcessingService(ILogger<ScopedProcessingService> logger)
        {
            _logger = logger;
        }        public void DoWork()
        {
            _logger.LogInformation($"Scoped Processing Service is working. {DateTime.Now}");
        }
    }

复制代码

 

复制代码

    public class ConsumeScopedServiceHostedService : IHostedService
    {        private readonly ILogger _logger;        public IServiceProvider Services { get; }        public ConsumeScopedServiceHostedService(IServiceProvider services, ILogger<ConsumeScopedServiceHostedService> logger)
        {
            Services = services;
            _logger = logger;
        }        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"Consume Scoped Service Hosted Service is starting. {DateTime.Now}");
            DoWork();            return Task.CompletedTask;
        }        private void DoWork()
        {
            _logger.LogInformation($"Consume Scoped Service Hosted Service is working. {DateTime.Now}");            using (IServiceScope scope = Services.CreateScope())//创建一个作用域.
            {
                IScopedProcessingService scopedProcessingService = scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();
                scopedProcessingService.DoWork();
            }
        }        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation($"Consume Scoped Service Hosted Service is stopping. {DateTime.Now}");            return Task.CompletedTask;
        }
    }

复制代码

 

但是我真的没搞懂官方这个例子的作用.因为托管服务只会激活一次,有作用域又有什么价值呢?希望哪位大哥能解答一下.

 

 

下面的在摘自网络:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_11.html

经测试:

  1. 当IIS上部署的项目启动后,后台任务随之启动,任务执行相应的log正常输出。

  2. 手动回收对应的应用程序池,任务执行相应的log输出停止。

  3. 重新请求该网站,后台任务随之启动,任务执行相应的log重新开始输出。

所以不建议在这样的后台任务中做一些需要固定定时执行的业务处理类的操作,但对于缓存刷新类的操作还是可以的,因为当应用程序池回收后再次运行的时候,后台任务会随着启动。

原文出处:https://www.cnblogs.com/refuge/p/10226911.html  

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消