ASP.NET Core 中的应用程序启动代码

Posted

技术标签:

【中文标题】ASP.NET Core 中的应用程序启动代码【英文标题】:Application startup code in ASP.NET Core 【发布时间】:2016-12-27 02:21:16 【问题描述】:

阅读documentation for ASP.NET Core,为启动选择了两种方法:Configure 和 ConfigureServices。

这些似乎都不是放置我想在启动时运行的自定义代码的好地方。也许我想在我的数据库中添加一个自定义字段(如果它不存在)、检查特定文件、将一些数据植入我的数据库等。我想在应用程序启动时运行一次的代码。

是否有首选/推荐的方法来执行此操作?

【问题讨论】:

添加此评论,因为我觉得它有助于保持 Startup.cs 文件干净,以获得已接受的解决方案:odetocode.com/blogs/scott/archive/2016/08/30/… 我知道这是在 2016 年提出的,但同样的问题在 2018 年仍然存在,您应该考虑我提出的观点并重新考虑接受的答案。 【参考方案1】:

此类自定义代码在启动时基本上有两个入口点。

1.) Main 方法

作为一个 ASP.NET Core 应用程序有很好的旧 Main 方法作为入口点,您可以在 ASP.NET Core 启动内容之前放置代码,例如

public class Program

    public static void Main(string[] args)
    
        // call custom startup logic here
        AppInitializer.Startup();

        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    

2.) 使用您的 Startup

正如您在问题中所述,ConfigureConfigureServices 是您自定义代码的好地方。

我更喜欢Startup 类。从运行时的角度来看,调用是在启动时调用还是在 host.Run() 调用之前的其他地方调用都没有关系。但从习惯于 ASP.NET 框架的程序员的角度来看,他首先寻找这种逻辑将是Startup.cs 文件。所有示例和模板都将身份、实体框架初始化等逻辑放在那里。因此,作为惯例,我建议将初始化的东西放在那里。

【讨论】:

Startup 类还提供了内置依赖注入容器IServiceProvider 通过IApplicationBuilder.ApplicationServices 属性在ConfigureServices 中可用的好处。 OP 说“这些似乎都不是放置自定义代码的好地方”,并不是说它们是一个好地方。【参考方案2】:

我同意 OP。

我的场景是我想向服务注册表注册一个微服务,但在微服务运行之前无法知道端点是什么。

我觉得 Configure 和 ConfigureServices 方法都不理想,因为它们都不是为了执行这种处理而设计的。

另一种情况是想要预热缓存,这也是我们可能想要做的事情。

接受的答案有几种选择:

创建另一个在您的网站之外执行更新的应用程序,例如部署工具,它在启动网站之前以编程方式应用数据库更新

在您的 Startup 类中,使用静态构造函数确保网站已准备好启动

更新

在我看来,最好的做法是像这样使用 IApplicationLifetime 接口:

public class Startup

    public void Configure(IApplicationLifetime lifetime)
    
        lifetime.ApplicationStarted.Register(OnApplicationStarted);
    

    public void OnApplicationStarted()
    
        // Carry out your initialisation.
    

【讨论】:

我发现一个请求处理已经开始了(它已经开始执行一个中间件),而 OnApplicationStarted 方法还没有完成。就我而言,它正在启动事务,而数据库尚未更新。 ApplicationStarted 文档还说:“在应用程序主机完全启动并即将等待正常关闭时触发。”这并不意味着在请求处理开始之前它不是一些初始化东西的地方。 请注意,IApplicationLifetime 在 .NET 3.x 中已弃用,新接口现在称为:IHostApplicationLifetime【参考方案3】:

这可以通过创建一个IHostedService 实现并在您的启动类中使用IServiceCollection.AddHostedService&lt;&gt;() in ConfigureServices() 注册它来完成。

示例

using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;

public class MyInitializer : IHostedService

    public Task StartAsync(CancellationToken cancellationToken)
    
        // Do your startup work here

        return Task.CompletedTask;
    

    public Task StopAsync(CancellationToken cancellationToken)
    
        // We have to implement this method too, because it is in the interface

        return Task.CompletedTask;
    

using Microsoft.Extensions.DependencyInjection;

public class Startup

    public void ConfigureServices(IServiceCollection services)
    
        services.AddHostedService<MyInitializer>();
    

注意事项

在您的代码完成执行之前,不会启动主应用程序。 构造函数依赖注入可用于IHostedService 实现。 我可以推荐这篇博文了解更多信息,以及如何使用异步的示例:https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-3/ 有关更多背景阅读,请参阅此讨论:https://github.com/dotnet/aspnetcore/issues/10137

【讨论】:

以上是关于ASP.NET Core 中的应用程序启动代码的主要内容,如果未能解决你的问题,请参考以下文章

细说.net core Startup

如何从 Asp.NET Core 3.1 启动类访问 launchSettings.json 中的 `applicationUrl` 属性?

HTTP 错误 500.30 - ASP.NET Core 2.2 中的 ANCM 进程内启动失败错误

HTTP 错误 500.30 - ASP.NET Core 5 应用程序无法启动

ASP.NET Core启动地址配置方法及优先级顺序 | .NET 6 版本

ASP.NET Core启动地址配置方法及优先级顺序