博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET Core 2.1 : 十一. 如何在后台运行一个任务
阅读量:7064 次
发布时间:2019-06-28

本文共 6296 字,大约阅读时间需要 20 分钟。

原文:

  在大部分程序中一般都会需要用到后台任务, 比如定时更新缓存或更新某些状态。()

一、应用场景

  以调用微信公众号的Api为例, 经常会用到access_token,官方文档这样描述:“是公众号的全局唯一接口调用凭据,有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效,建议公众号开发者使用中控服务器统一获取和刷新Access_token,其他业务逻辑服务器所使用的access_token均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致access_token覆盖而影响业务。”

  在这个场景中我们可以创建一个后台运行的服务,按照access_token的有效期定时执行去请求获取新的access_token并存储,其他所有需要用到这个access_token的都到这个共有的access_token。

二、实现方式(一)

  ASP.NET Core 在2.0的时候就提供了一个名为IHostedService的接口,我们要做的只有两件事:

    1. 实现它。

    2. 将这个接口实现注册到依赖注入服务中。

  A. 实现IHostedService的接口

            首先看一下这个IHostedService:

public interface IHostedService    {        Task StartAsync(CancellationToken cancellationToken);        Task StopAsync(CancellationToken cancellationToken);    }

通过名字就可以看出来,一个是这个服务启动的时候做的操作,另一个则是停止的时候。

新建一个类 TokenRefreshService  实现 IHostedService ,如下面代码所示:

1     internal class TokenRefreshService : IHostedService, IDisposable 2     { 3         private readonly ILogger _logger; 4         private Timer _timer; 5  6         public TokenRefreshService(ILogger
logger) 7 { 8 _logger = logger; 9 }10 11 public Task StartAsync(CancellationToken cancellationToken)12 {13 _logger.LogInformation("Service starting");14 _timer = new Timer(Refresh, null, TimeSpan.Zero,TimeSpan.FromSeconds(5));15 return Task.CompletedTask;16 }17 18 private void Refresh(object state)19 {20 _logger.LogInformation(DateTime.Now.ToLongTimeString() + ": Refresh Token!"); //在此写需要执行的任务21 22 }23 24 public Task StopAsync(CancellationToken cancellationToken)25 {26 _logger.LogInformation("Service stopping");27 _timer?.Change(Timeout.Infinite, 0);28 return Task.CompletedTask;29 }30 31 public void Dispose()32 {33 _timer?.Dispose();34 }35 }

既然是定时刷新任务,那么就用了一个timer, 当服务启动的时候启动它,由它定时执行Refresh方法来获取新的Token。

这里为了方便测试写了5秒执行一次, 实际应用还是读取配置文件比较好, 结果如下:

BackService.TokenRefreshService:Information: 17:23:30: Refresh Token!BackService.TokenRefreshService:Information: 17:23:35: Refresh Token!BackService.TokenRefreshService:Information: 17:23:40: Refresh Token!BackService.TokenRefreshService:Information: 17:23:45: Refresh Token!BackService.TokenRefreshService:Information: 17:23:50: Refresh Token!

 B. 在依赖注入中注册这个服务。

在Startup的ConfigureServices中注册这个服务,如下代码所示:

services.AddSingleton
();

 

三、实现方式(二)

 在 ASP.NET Core 2.1中, 提供了一个名为 BackgroundService  的类,它在 Microsoft.Extensions.Hosting 命名空间中,查看一下它的源码:

1 using System; 2 using System.Threading; 3 using System.Threading.Tasks; 4  5 namespace Microsoft.Extensions.Hosting 6 { 7     ///  8     /// Base class for implementing a long running 
. 9 ///
10 public abstract class BackgroundService : IHostedService, IDisposable11 {12 private Task _executingTask;13 private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource();14 15 /// 16 /// This method is called when the
starts. The implementation should return a task that represents17 /// the lifetime of the long running operation(s) being performed.18 ///
19 /// Triggered when
is called.20 ///
A
that represents the long running operations.
21 protected abstract Task ExecuteAsync(CancellationToken stoppingToken);22 23 /// 24 /// Triggered when the application host is ready to start the service.25 /// 26 /// Indicates that the start process has been aborted.27 public virtual Task StartAsync(CancellationToken cancellationToken)28 {29 // Store the task we're executing30 _executingTask = ExecuteAsync(_stoppingCts.Token);31 32 // If the task is completed then return it, this will bubble cancellation and failure to the caller33 if (_executingTask.IsCompleted)34 {35 return _executingTask;36 }37 38 // Otherwise it's running39 return Task.CompletedTask;40 }41 42 /// 43 /// Triggered when the application host is performing a graceful shutdown.44 /// 45 /// Indicates that the shutdown process should no longer be graceful.46 public virtual async Task StopAsync(CancellationToken cancellationToken)47 {48 // Stop called without start49 if (_executingTask == null)50 {51 return;52 }53 54 try55 {56 // Signal cancellation to the executing method57 _stoppingCts.Cancel();58 }59 finally60 {61 // Wait until the task completes or the stop token triggers62 await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));63 }64 }65 66 public virtual void Dispose()67 {68 _stoppingCts.Cancel();69 }70 }71 }

可以看出它一样是继承自 IHostedService, IDisposable , 它相当于是帮我们写好了一些“通用”的逻辑, 而我们只需要继承并实现它的 ExecuteAsync 即可。

也就是说,我们只需在这个方法内写下这个服务需要做的事,这样上面的刷新Token的Service就可以改写成这样:

1     internal class TokenRefreshService : BackgroundService 2     { 3         private readonly ILogger _logger; 4  5         public TokenRefreshService(ILogger
logger) 6 { 7 _logger = logger; 8 } 9 10 protected override async Task ExecuteAsync(CancellationToken stoppingToken)11 {12 _logger.LogInformation("Service starting");13 14 while (!stoppingToken.IsCancellationRequested)15 {16 _logger.LogInformation(DateTime.Now.ToLongTimeString() + ": Refresh Token!");//在此写需要执行的任务17 await Task.Delay(5000, stoppingToken);18 }19 20 _logger.LogInformation("Service stopping");21 }22 }

是不是简单了不少。(同样这里为了方便测试写了5秒执行一次)

四. 注意事项

感谢 咿呀咿呀哟在评论中的提醒,当项目部署在IIS上的时候, 当应用程序池回收的时候,这样的后台任务也会停止执行。

经测试:

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

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

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

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

 

 

地址

转载地址:http://azill.baihongyu.com/

你可能感兴趣的文章
get方式和set方式提交时乱码
查看>>
REST与SOA两种架构下WCF的异同比较(含源码)
查看>>
遇事处理方式
查看>>
五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT)
查看>>
linux 如何查看服务和端口
查看>>
Linux中如何让进程(或正在运行的程序)到后台运行?[zz]
查看>>
ZendGuardLoader安装
查看>>
floyd算法&迪杰斯特拉算法
查看>>
[CareerCup] 17.8 Contiguous Sequence with Largest Sum 连续子序列之和最大
查看>>
加入强调语气,使用<strong>和<em>标签
查看>>
How Spring Boot Autoconfiguration Magic Works--转
查看>>
Android 最简单的SD卡文件遍历程序
查看>>
ArcGIS Engine开发之旅03--ArcGIS Engine中的控件
查看>>
sparkR 跑通的函数
查看>>
jQ效果:jQuery之插件开发短信发送倒计时功能
查看>>
aar
查看>>
(第9篇)大数据的的超级应用——数据挖掘-推荐系统
查看>>
Solr In Action 中文版 第一章(四、五)
查看>>
[GIT]
查看>>
VI 你不知道的事
查看>>