加入收藏 | 设为首页 | 会员中心 | 我要投稿 航空爱好网 (https://www.ikongjun.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > Asp教程 > 正文

如何在ASP.NET Core程序启动时运行异步任务

发布时间:2022-10-27 12:53:08 所属栏目:Asp教程 来源:
导读:  背景

  当我们做项目的时候,有时候希望自己的ASP.NET Core应用在启动前执行一些初始化逻辑。例如,你希望验证配置是否合法,填充缓存数据,或者运行数据库迁移脚本。在本篇博客中,我将介绍几种可选的方案
  背景
 
  当我们做项目的时候,有时候希望自己的ASP.NET Core应用在启动前执行一些初始化逻辑。例如,你希望验证配置是否合法,填充缓存数据,或者运行数据库迁移脚本。在本篇博客中,我将介绍几种可选的方案,并且通过展示一些简单的方法和扩展点来说明我想要解决的问题。
 
  开始我将先描述一下ASP.NET Core内置的解决方案,使用IStartupFilter来运行同步任务。然后我将描述几种可选的执行异步任务的方案。你可以(但是可能不应该这样做)使用IStartupFilter或者IApplicationLifetime事件来执行异步任务。你也可以使用IHostService接口来运行一次性任务且不会阻塞ASP.NET Core应用启动。最后唯一合理的方案是在program.cs文件中手动运行任务。在下一篇博客中,我会展示一个可以简化这个流程的推荐方案。
 
  为什么我们需要在程序启动时运行异步任务?
 
  在程序启动,开始监听请求之前,运行一些初始化代码是非常普遍的。对于一个ASP.NET Core应用程序,启动前有许多任务需要运行,例如:
 
  以上几步都四发生在应用程序引导时。然而有些一次性任务需要在WebHost启动,监听请求前运行。例如
 
  有些时候,一些任务并不是非要在程序启动,监听请求前运行。这里我们以填充缓存为例,如果它是设计的比较好的话,在程序启动前是否填充缓存数据是无关紧要的。但是,相对的,你肯定也希望在应用程序开始监听请求之前,迁移你的数据库!
 
  其实ASP.NET Core框架自己也需要运行一些一次性初始化任务。这个最好的例子就是数据保护,它常用来做数据加密,这个模块必须要在应用启动前初始化。为了实现初始化,它们使用了IStartupFilter。
 
  使用IStartupFilter来运行同步任务
 
  在之前的博客中,我已经介绍过IStartupFilter, 它是一个自定义ASP.NET Core应用的强力接口。
 
  如果你是第一次接触Filter, 我建议你去我之前的博客,这里我只会提供一个简短的总结。
 
  IStartupFilter会在配置中间件管道的进程中被执行(通常在Startup.Configure()中完成)。它们允许你通过插入额外的中间件,分叉或执行任何其他操作来自定义应用程序实际创建的中间件管道。例如下面代码展示的AutoRequestServiceStartupFilter
 
  asp殡葬网源码 带网上公墓的asp源码程序_asp程序rs()什么意思_ASP程序
 
  这非常有用,但它与ASP.NET Core应用程序启动时运行一次性任务有什么关系呢?
 
  IStartupFilter的主要功能是为开发人员提供了一个钩子(hook), 这个钩子触发的时机是在在应用程序配置完成并配置依赖注入容器之后,应用程序启动之前。这意味着,你可以在实现IStartupFilter的类中使用依赖注入,这样你就可以在这里完成许多希望在应用程序启用前需要运行的任务。以ASP.NET Core内置的DataProtectionStartupFilter为例,它会在程序启用前初始化整个数据保护模块。
 
  IStartupFilter提供的另外一个重要功能就是,它允许你通过向依赖注入容器注册服务来添加要执行的任务。这意味着如果你自己编写了一个Library, 你可以在应用程序启动时注册一个任务,而不需要应用程序显式调用它。
 
  问题是IStartupFilter基本上是同步的。Configure方法的返回值不是Task,因此我们只能使用同步方式执行异步任务,这显然不是好的实现方案。 我稍后会讨论这个,但现在让我们先跳过它。
 
  为什么不用健康检查?
 
  ASP.NET Core 2.2中加入了一个新的健康检查功能,它通过暴露一个HTTP节点,让你可以查询当前应用的健康状态。当应用部署之后,像Kubernetes这样的编排引擎或HAProxy和NGINX等反向代理可以查询此HTTP节点以检查你应用是否已准备好开始接收请求。
 
  你可以使用健康检查功能来确保你的应用程序不会开始处理请求,直到所有必需的一次性初始化任务完成为止。然而,这有一些缺点:
 
  在我看来,健康检查并不适合一次性任务的场景,他们可能对我描述的一些例子很有用,但我不认为它适用于所有情况。我真的希望能在WebHost启动之前,运行一些一次性任务。
 
  运行异步任务
 
  我已经花了很长的篇幅来讨论了所有不能完成我的目标的所有方法,那么哪些才是可行的方案!在这一节中,我将描述几种运行异步任务的方案(即方法返回Task, 并且需要等待的),其中有一些较好的方案,也有一些需要规避的方案。
 
  这里为了更清楚的描述这些方案,我选用数据库迁移作为例子。在EF Core中,你可以在运行时调用myDbContext.Database.MigrateAsync()来迁移数据库,其中myDbContext是当前应用程序的数据库上下文实例。
 
  EF还提供了一个同步的数据库迁移方法Database.Migrate(),但是这里我们不需要使用它。
 
  使用IStartupFilter
 
  我之前描述过如何使用IStartupFilter在应用程序启动时运行同步任务。 不过,这里为了异步方法,我们使用了GetAwaiter()和GetResult()阻塞了线程, 将异步方法变成了一个同步方法。
 
  警告:这是一种非常不好的异步实践方式
 
  asp殡葬网源码 带网上公墓的asp源码程序_ASP程序_asp程序rs()什么意思
 
  这段代码可能不会引起任何问题,它会在应用程序启动且未开始监听请求时运行,所以不太可能出现死锁。但是坦率的说,我会尽可能不用这种方式。
 
  使用IApplicationLifetime事件
 
  我之前还没有讨论过和这个事件相关的内容,但是当你的应用程序启动和关闭前,你可以使用IApplicationLifetime接口接收到通知。这里我不会详细介绍它,因为使用它来实现我们的目的会有一些问题。
 
  IApplicationLifetime使用CancellationTokens来注册回调,这意味着你只能同步执行回调。 这实际上意味着无论你做什么,你都会遇到同步异步模式。
 
  ApplicationStarted事件仅在WebHost启动后触发,因此任务在应用程序开始接受请求后运行。
 
  鉴于他们没有解决IStartupFilter使用同步方式处理异步任务的问题,也没有阻止应用启动,所以我只是将它列出来仅供参考。
 
  使用IHostedService运行异步事件
 
  IHostService允许在ASP.NET Core应用程序生命周期内,以后台程序的方式执行长时间运行的任务。它有许多不同的用途,你可以使用它在计数器上运行定期任务,或者监听RabbitMQ消息。在ASP.NET Core 3.0中, Web Host也可能是使用IHostService构建的。
 
  IHostService本质上是异步的ASP程序,他提供了StartAsync和StopAsync方法。这对我们来说非常的有用,它再在是使用同步方式处理异步任务了。使用IHostService,我们的数据库迁移任务可以变成一个托管服务。
 
  ASP程序_asp程序rs()什么意思_asp殡葬网源码 带网上公墓的asp源码程序
 
  不幸的是,IHostedService并不是我们希望的灵丹妙药。 它允许我们编写真正的异步代码,但它有几个问题:
 
  在Program.cs中手动运行任务
 
  到现在为止,我们都没有提供一种完善的解决方案,他们或者是使用同步方式处理异步任务,或者是不能阻止程序启动。
 
  现在让我们停止尝试使用框架机制,手动来完成工作。
 
  ASP.NET Core模板中使用的默认Program.cs在Main函数的一个语句中构建并运行IWebHost:
 
  asp殡葬网源码 带网上公墓的asp源码程序_asp程序rs()什么意思_ASP程序
 
  这里你可能会发现在Build()方法之后,Run()方法之前,你可以添加一些自定义的代码,再加上C# 7.1中允许使用异步方式运行Main方法,所以这里我们有了一个合理的方案。
 
  asp程序rs()什么意思_ASP程序_asp殡葬网源码 带网上公墓的asp源码程序
 
  这个方案有以下优点:
 
  但是这种方法也存在一些问题:
 
  如果这些问题都不是问题,那么我认为这个最终选项提供了解决问题的最佳方案。 在我的下一篇文章中,我将展示一些方法,我们可以在这个例子的基础上构建,以使某些内容更容易使用。
 
  总结
 
  在这篇文章中,我讨论了在ASP.NET Core应用程序启动时执行异步运行任务的必要性。 我描述了这样做的一些问题和挑战。 对于同步任务,IStartupFilter为ASP.NET Core应用程序启动过程提供了一个有用的钩子,但是需要使用同步方式运行异步任务,这通常是一个坏主意。 我描述了运行异步任务的一些可能的选项,我发现其中最好的是在Program.cs中“手动”运行任务。 在下一篇文章中,我将介绍一些代码,使这个模式更容易使用。
 

(编辑:航空爱好网)

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

    推荐文章