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();
}
例如:
- 从代码迁移数据库
- 静态缓存初始化
- 种子申请到数据库
- root账号认证,
- ...
我目前对 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的版本,一不小心切换到低版本会很痛苦。
如果您熟悉生产代码,您总会遇到需要在服务中 requested/processed 之前调用的逻辑。
我个人将它包装成这样的东西并从 DI 框架中调用它:
public interface IMigrator
{
Task UpdateAsync();
}
例如:
- 从代码迁移数据库
- 静态缓存初始化
- 种子申请到数据库
- root账号认证,
- ...
我目前对 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的版本,一不小心切换到低版本会很痛苦。