绍兴网站建设设计制作,超人气网站是这样建成的,比wordpress好,wordpress当前网址函数原文#xff1a;Running async tasks on app startup in ASP.NET Core (Part 2)作者#xff1a;Andrew Lock译者#xff1a;Lamond Lu在我的上一篇博客中#xff0c;我介绍了如何在ASP.NET Core应用程序启动时运行一些一次性异步任务。本篇博客将继续讨论上一篇的内容… 原文Running async tasks on app startup in ASP.NET Core (Part 2)作者Andrew Lock译者Lamond Lu在我的上一篇博客中我介绍了如何在ASP.NET Core应用程序启动时运行一些一次性异步任务。本篇博客将继续讨论上一篇的内容如果你还没有读过我建议你先读一下前一篇。在本篇博客中我将展示上一篇博文中提出的“在Program.cs中手动运行异步任务”的实现方法。该实现会使用一些简单的接口和类来封装应用程序启动时的运行任务逻辑。我还会展示一个替代方法这个替代方法是在Kestral服务器启动时使用IServer接口。在应用程序启动时运行异步任务这里我们先回顾一下上一遍博客内容在上一篇中我们试图寻找一种方案允许我们在ASP.NET Core应用程序启动时执行一些异步任务。这些任务应该是在ASP.NET Core应用程序启动之前执行但是由于这些任务可能需要读取配置或者使用服务所以它们只能在ASP.NET Core的依赖注入容器配置完成后执行。数据库迁移填充缓存都可以这种异步任务的使用场景。我们在一篇文章的末尾提出了一个相对完善的解决方案这个方案是在Program.cs中“手动”运行任务。运行任务的时机是在IWebHostBuilder.Build()和IWebHost.RunAsync()之间。这种实现方式是可行的但是有点乱。这里我们将许多不应该属于Program.cs职责的代码放在了Program.cs中让它看起来有点臃肿了所以这里我们需要将数据库迁移相关的代码移到另外一个类中。这里更麻烦的问题是我们必须要手动调用任务。如果你在多个应用程序中使用相同的模式那么最好能改成自动调用任务。在依赖注入容器中注册启动任务这里我将使用基于IStartupFilter和IHostService使用的模式。它们允许你在依赖注入容器中注册它们的实现类并在应用程序启动前获取到这些接口的所有实现类并依次执行它们。所以这里首先我们创建一个简单的接口来启动任务。并且创建一个在依赖注入容器中注册任务的便捷方法。最后我们添加一个扩展方法在应用程序启动时找到所有已注册的IStartupTasks按顺序运行它们然后启动IWebHost以上就是所有的代码。下面为了看一下它的实际效果我将继续使用上一篇中EF Core数据库迁移的例子例子异步迁移数据库实现IStartupTask和实现IStartupFilter非常的相似。你可以从依赖注入容器中注入服务。为了使用依赖注入容器中的服务这里我们需要手动注入一个IServiceProvider对象并手动创建一个Scoped服务。EF Core的数据库迁移启动任务类似以下代码现在我们可以在ConfigureServices方法中使用依赖注入容器添加启动任务了。最后我们更新一下Program.cs, 使用RunWithTasksAsync()方法替换Run()方法。以上代码利用了C# 7.1中引入的异步Task Main的特性。从功能上来说它与我上一篇博客中的手动代码等同但是它有一些优点。它的任务实现代码没有放在Program.cs中。由于上一条的优点开发人员可以很容易的添加额外的任务。如果不运行任何任务它的功能和RunAsync是一样的对于以上方案有一个问题需要注意。这里我们定义的任务会在IConfiguration和依赖注入容器配置完成之后运行这也就意味着当任务执行时所有的IStartupFilter都没有运行中间件管道也没有配置。就我个人而言我不认为这是一个问题因为我暂时想不出任何可能。到目前为止我所编写的任务都不依赖于IStartupFilter和中间件管道。但这也并不意味着没有这种可能。不幸的是使用当前的WebHost代码并没有简单的方法尽管 在.NET Core 3.0中当ASP.NET Core作为IHostedService运行时这可能会发生变化。 问题是应用程序是引导通过配置中间件管道并运行IStartupFilters和启动在同一个函数中。 当你在Program.cs中调用WebHost.Run()时在内部程序会调用WebHost.StartAsync如下所示为简洁起见,其中只包含了日志记录和一些其他次要代码这里问题是我们想要在BuildApplication()和Server.StartAsync之间插入代码但是现在没有这样做的机制。我不确定我所给出的解决方案是否优雅但它可以工作并为消费者提供更好的体验因为他们不需要修改Program.cs使用IServer的替代方案为了实现在BuildApplication()和Server.StartAsync()之间运行异步代码我能想到的唯一办法是我们自己的实现一个IServer实现Kestrel 对你来说听到这个可能感觉非常可怕 - 但是我们真的不打算更换服务器我们只是去装饰它。TaskExecutingServer在其构造函数中获取了一个IServer实例 - 这是ASP.NET Core注册的原始Kestral服务器。我们将大部分IServer的接口实现直接委托给Kestrel我们只是拦截对StartAsync的调用并首先运行注入的任务。这个实现最困难部分是使装饰器正常工作。正如我在上一篇文章中所讨论的那样使用带有默认ASP.NET Core容器的装饰可能会非常棘手。我通常使用Scrutor来创建装饰器但是如果你不想依赖另一个库你总是可以手动进行装饰 但一定要看看Scrutor是如何做到这一点的下面我们添加一个用于添加IStartupTask的扩展方法 这个扩展方法做了两件事一是将IStartupTask注册到依赖注入容器中二是装饰了之前注册的IServer实例这里为了简洁我省略了Decorate方法的实现。如果它发现IServer已经被装饰它会跳过第二步这样你就可以安全的多次调用AddStartupTaskT方法。使用这两段代码我们不再需要再对Program.cs文件进行任何更改并且我们是在完全构建应用程序后执行我们的任务这其中也包括IStartupFilters和中间件管道。启动过程的序列图现在看起来有点像这样以上就是这种实现方式全部的内容。它的代码非常少, 以至于我自己都在考虑是否要自己编写一个库。不过最后我还是在GitHub和Nuget上创建了一个库NetEscapades.AspNetCore.StartupTasks这里我只编写了使用后一种IServer实现的库因为它更容易使用而且Thomas Levesque已经编写针对第一种方法可用的NuGet包。在GitHub的实现中我手动构造了装饰器以避免强制依赖Scrutor。 但最好的方法可能就是将代码复制并粘贴到您自己的项目中。总结在这篇博文中我展示了两种在ASP.NET Core应用程序启动时异步运行任务的方法。 第一种方法需要稍微修改Program.cs但是“更安全”因为它不需要修改像IServer这样的内部实现细节。 第二种方法是装饰IServer提供更好的用户体验但感觉更加笨拙。