在大部分程序中一般都会需要用到后台任务, 比如定时更新缓存或更新某些状态。(ASP.NET Core 系列目录

一、应用场景

  以调用微信公众号的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 ,如下面代码所示:

     internal class TokenRefreshService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer; public TokenRefreshService(ILogger<TokenRefreshService> logger)
{
_logger = logger;
} public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Service starting");
_timer = new Timer(Refresh, null, TimeSpan.Zero,TimeSpan.FromSeconds());
return Task.CompletedTask;
} private void Refresh(object state)
{
_logger.LogInformation(DateTime.Now.ToLongTimeString() + ": Refresh Token!"); //在此写需要执行的任务 } public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Service stopping");
_timer?.Change(Timeout.Infinite, );
return Task.CompletedTask;
} public void Dispose()
{
_timer?.Dispose();
}
}

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

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

BackService.TokenRefreshService:Information: ::: Refresh Token!
BackService.TokenRefreshService:Information: ::: Refresh Token!
BackService.TokenRefreshService:Information: ::: Refresh Token!
BackService.TokenRefreshService:Information: ::: Refresh Token!
BackService.TokenRefreshService:Information: ::: Refresh Token!

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

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

services.AddSingleton<IHostedService, TokenRefreshService>();

三、实现方式(二)

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

 using System;
using System.Threading;
using System.Threading.Tasks; namespace Microsoft.Extensions.Hosting
{
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
private Task _executingTask;
private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource(); /// <summary>
/// This method is called when the <see cref="IHostedService"/> starts. The implementation should return a task that represents
/// the lifetime of the long running operation(s) being performed.
/// </summary>
/// <param name="stoppingToken">Triggered when <see cref="IHostedService.StopAsync(CancellationToken)"/> is called.</param>
/// <returns>A <see cref="Task"/> that represents the long running operations.</returns>
protected abstract Task ExecuteAsync(CancellationToken stoppingToken); /// <summary>
/// Triggered when the application host is ready to start the service.
/// </summary>
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
public virtual Task StartAsync(CancellationToken cancellationToken)
{
// Store the task we're executing
_executingTask = ExecuteAsync(_stoppingCts.Token); // If the task is completed then return it, this will bubble cancellation and failure to the caller
if (_executingTask.IsCompleted)
{
return _executingTask;
} // Otherwise it's running
return Task.CompletedTask;
} /// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// </summary>
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
// Stop called without start
if (_executingTask == null)
{
return;
} try
{
// Signal cancellation to the executing method
_stoppingCts.Cancel();
}
finally
{
// Wait until the task completes or the stop token triggers
await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken));
}
} public virtual void Dispose()
{
_stoppingCts.Cancel();
}
}
}

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

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

     internal class TokenRefreshService : BackgroundService
{
private readonly ILogger _logger; public TokenRefreshService(ILogger<TokenRefresh2Service> logger)
{
_logger = logger;
} protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Service starting"); while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation(DateTime.Now.ToLongTimeString() + ": Refresh Token!");//在此写需要执行的任务
await Task.Delay(, stoppingToken);
} _logger.LogInformation("Service stopping");
}
}

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

四. 注意事项

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

经测试:

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

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

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

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

github地址

ASP.NET Core 2.1 : 十一. 如何在后台运行一个任务的更多相关文章

  1. [ASP.NET Core 3框架揭秘] 依赖注入[4]:一个Mini版的依赖注入框架

    在前面的章节中,我们从纯理论的角度对依赖注入进行了深入论述,我们接下来会对.NET Core依赖注入框架进行单独介绍.为了让读者朋友能够更好地理解.NET Core依赖注入框架的设计与实现,我们按照类 ...

  2. 如果你想深刻理解ASP.NET Core请求处理管道,可以试着写一个自定义的Server

    我们在上面对ASP.NET Core默认提供的具有跨平台能力的KestrelServer进行了详细介绍(<聊聊ASP.NET Core默认提供的这个跨平台的服务器——KestrelServer& ...

  3. ASP.NET Core MVC应用程序中的后台工作任务

    在应用程序的内存中缓存常见数据(如查找)可以显着提高您的MVC Web应用程序性能和响应时间.当然,这些数据必须定期刷新. 当然你可以使用任何方法来更新数据,例如Redis中就提供了设定缓存对象的生命 ...

  4. 解决ASP.NET Core部署到IIS,更新项目"另一个程序正在使用此文件,进程无法访问"

    问题:部署到IIS上的ASP.NET Core项目,在更新的时候会进程占用的错误 初步解决方案: 1,关闭应用程序池 2,关闭网站 3,更新项目 缺点:网站没法访问,部署项目停的时间过长 查询官方文档 ...

  5. ASP.NET Core系列(二):创建第一个.Net Core 项目

    前面讲过 .NET Core简介及开发环境安装,本章会讲一讲ASP.NET Core 2.0的项目结构,查看完整的ASP.NET Core系列文章:https://www.cnblogs.com/zh ...

  6. 基于ASP.Net Core开发的一套通用后台框架

    基于ASP.Net Core开发一套通用后台框架 写在前面 这是本人在学习的过程中搭建学习的框架,如果对你有所帮助那再好不过.如果您有发现错误,请告知我,我会第一时间修改. 知其然,知其所以然,并非重 ...

  7. 【低码】asp.net core 实体类可生产 CRUD 后台管理界面

    前言介绍 喜欢小规模团队的"单打独斗",有的时候即使在大公司,也经常做着3-5个人团队的小项目,相信很多人有类似的经历. 本文介绍如何将项目中已存在的[实体类],直接生产出 CRUD 后台管理界面. ...

  8. ASP.NET Core SignalR :学习消息通讯,实现一个消息通知

    什么是 SignalR 目前我用业余时间正在做一个博客系统,其中有个功能就是评论通知,就是假如A用户评论B用户的时候,如果B用户首页处于打开状态,那么就会提示B用户有未读消息.暂时用SignalR来实 ...

  9. ASP.NET CORE dotnet run 命令使用debug方式运行

    由于我的开发环境比较复杂,每次调试一套项目都要启动好几个VS,比较繁琐,今天决定换一种方式调试,对于不该改动的代码的附加项目直接使用dotnet run命令以debug的运行方式运行, 一开始无法运行 ...

随机推荐

  1. 8.3-8.4NOIP模拟题总结

    一:成绩 Day1 score=100+100+20 Day2 score=100+30+0 这成绩还是不行啊,仍需继续加油(抱怨一句暴力分有点少#滑稽) 二:题目分析 Day1 T1祖孙询问: 已知 ...

  2. centos7安装tomcat8.5

    1.下载 tomcat Linux 版本 tomcat 官网下载地址:http://tomcat.apache.org/download-80.cgi 百度云盘链接:链接: https://pan.b ...

  3. 封装redis

    封装redis import redis # r = redis.Redis() class MyRedis(): def __init__(self,ip,password,port=6379,db ...

  4. Java之hashCode的作用和equals方法的重构规则

    这个是博主对hashcode的初步理解,以后加深了会再来更新: 1.hashcode是什么? hashcode是对象的散列码,不同的对象几乎不一样,说几乎是因为还是可以一样的. 特点:每一个对象都有h ...

  5. dedecms自定义模型内容调用多个Ueditor

    关于dedecms后台如何整合百度编辑器(ueditor)网上有很多了,本站就不再赘述了,主要问题是,涉及到如果有内容模型的修改,则按照网络上介绍的方法会发现有BUG.当修改过默认的文章模型或者其他模 ...

  6. HBuilder git合作-上传项目到Git Hub

    1.初始项目的创建 这里假设你已经在Git Hub上面建立好了代码的远程仓库,并已经邀请好了队员 在HBuidler中创建好初始的项目,然后右键,"Team"->" ...

  7. JavaMail技术实现邮件发送转【】

    1.导入2个jar包,mail.jar,activation.jar 2.导入的jar包与myeclipse中自带的javaee 中的javaee.jar中的javax.activation包及jav ...

  8. SQL Server索引碎片整理实际操作记录

    SQL Server 版本是 2008 R2. 查询数据库索引碎片情况的 SQL 语句(来源): SELECT OBJECT_NAME(ind.OBJECT_ID) AS TableName, ind ...

  9. python 模拟豆瓣登录(豆瓣6.0)

    最近在学习python爬虫,看到网上有很多关于模拟豆瓣登录的例子,随意找了一个试了下,发现不能运行,对比了一下代码和豆瓣网站,发现原来是豆瓣网站做了修改,增加了反爬措施. 首先看下要模拟登录的网站: ...

  10. Java数据结构和算法 - 哈希表

    Q: 如何快速地存取员工的信息? A: 假设现在要写一个程序,存取一个公司的员工记录,这个小公司大约有1000个员工,每个员工记录需要1024个字节的存储空间,因此整个数据库的大小约为1MB.一般的计 ...