ASP.NET Core Web Api 中的初始化步骤放在哪里?

Where to put your initialization steps in ASP.NET Core Web Api?

如果您熟悉生产代码,您总会遇到需要在服务中 requested/processed 之前调用的逻辑。

我个人将它包装成这样的东西并从 DI 框架中调用它:

public interface IMigrator
{
    Task UpdateAsync();
}

例如:

我目前对 Web API 框架不是很精通,我需要知道,应该将逻辑放在哪里?在Startup.Configure?合适吗?如果需要,比如 10 分钟,结果如何?

需要您的建议:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services
            .AddControllers();
            services.Register(new CoreModule(), new DataModule());
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "api",
                pattern: "api/v1/{controller}/{action}/{id?}");
        });

        //<- somewhere here? does it break some startup logic in IIS like winservices does when process takes longer than 1 minute?
        await _migrator.UpdateAsync();
    }
}

编辑:

找到了相关文章,其中描述了应该如何进行初始化以及在何处进行初始化。以及如何执行此异步操作 - https://andrewlock.net/running-async-tasks-on-app-startup-in-asp-net-core-part-1/

为了回答你的问题,我举了一个在启动时应用迁移的例子。你可以使用相同的概念。

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<DataContext>(x => x.UseSqlite("Data Source=LocalDatabase.db"));

    ...
}

将作为参数注入 Configure() 方法的 EF Core DB 上下文服务实例。

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
    // migrate any database changes on startup (includes initial db creation)
    dataContext.Database.Migrate();

    ...
}

在上面的 link 中找到了答案。从 .Net Core 3.0 开始,我们可以使用 IHostedService 接口,特别是对于那些任务。重要注意事项是较低版本 不适合,因为它们在服务用户请求之前不等待 StartAsync 方法完成:

internal sealed class Boot : IHostedService
{
   public Task StartAsync(CancellationToken token){
       //migrate db or whatever here
   }

   public Task StopAsync(CancellationToken token){
       //gracefull shutdown for 5 sec, after which token will blowup. It will still wait for method return.
   }
}

然后在你的DI中注册并配置方法:

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddSingleton<IBoot, Boot>();
        services.AddHostedService(x=> x.GetService<IBoot>());
    }

高手:

  • 同步上下文中的异步等待没有魔力。一切async/cancellable,非死锁。
  • 它可以正常关闭,以防您在初始化过程中持有一些需要处理的非托管资源或其他资源。
  • 它完全支持依赖注入。

缺点:

  • 异常时不会调用 StopAsync。注意,Dispose也要用
  • 注意framework的版本,一不小心切换到低版本会很痛苦。