mor*_*eng 6 c# .net-core asp.net-core asp.net-core-hosted-services
我有一个 .NET Core 3.1 应用程序,它提供一个描述应用程序运行状况的端点,以及一个处理数据库中数据的 IHostedService。但是有一个问题,HostedService 的 worker 函数开始处理很长时间,导致Configure()Startup 中的方法没有被调用,/status端点没有运行。
我希望/status端点在 HostedService 启动之前开始运行。如何在托管服务之前启动端点?
示例代码
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<SomeHostedProcessDoingHeavyWork>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/status", async context =>
{
await context.Response.WriteAsync("OK");
});
});
}
}
Run Code Online (Sandbox Code Playgroud)
托管服务
public class SomeHostedProcessDoingHeavyWork : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await MethodThatRunsForSeveralMinutes();
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
private async Task MethodThatRunsForSeveralMinutes()
{
// Process data from db....
return;
}
}
Run Code Online (Sandbox Code Playgroud)
我试图探索在 中添加 HostedService Configure(),但它app.ApplicationServices是一个 ServiceProvider,因此是只读的。
use*_*411 10
我认为提出的解决方案是一种解决方法。
如果您在 ConfigureServices()中添加托管服务,它将在Kestrel之前启动,因为当您调用时, GenericWebHostService(实际上运行Kestrel)会添加到Program.cs中
.ConfigureWebHostDefaults(webBuilder =>
webBuilder.UseStartup<Startup>()
)
Run Code Online (Sandbox Code Playgroud)
所以它总是最后添加。
要在 Kestrel之后启动托管服务,只需将另一个调用链接到
.ConfigureServices(s => s.AddYourServices())
拨打电话后ConfigureWebHostDefaults()。
像这样的东西:
IHostBuilder hostBuilder = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
.ConfigureServices(s => {
s.AddHostedService<SomeHostedProcessDoingHeavyWork>();
});
Run Code Online (Sandbox Code Playgroud)
你应该完成了。
我最终使用Task.Yield()并实现了一个抽象类来封装它,并带有可选的PreExecuteAsyncInternal钩子和错误处理程序ExecuteAsyncExceptionHandler
public abstract class AsyncBackgroundService : BackgroundService
{
protected ILogger _logger;
private readonly TimeSpan _delay;
protected AsyncBackgroundService(ILogger logger, TimeSpan delay)
{
_logger = logger;
_delay = delay;
}
public virtual Task PreExecuteAsyncInternal(CancellationToken stoppingToken)
{
// Override in derived class
return Task.CompletedTask;
}
public virtual void ExecuteAsyncExceptionHandler(Exception ex)
{
// Override in derived class
}
public abstract Task ExecuteAsyncInternal(CancellationToken stoppingToken);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Prevent BackgroundService from locking before Startup.Configure()
await Task.Yield();
_logger.LogInformation("Running...");
await PreExecuteAsyncInternal(stoppingToken);
while (!stoppingToken.IsCancellationRequested)
{
try
{
await ExecuteAsyncInternal(stoppingToken);
await Task.Delay(_delay, stoppingToken);
}
catch (TaskCanceledException)
{
// Deliberate
break;
}
catch (Exception ex)
{
_logger.LogCritical($"Error executing {nameof(ExecuteAsyncInternal)} in {GetType().Name}", ex.InnerException);
ExecuteAsyncExceptionHandler(ex);
break;
}
}
_logger.LogInformation("Stopping...");
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2419 次 |
| 最近记录: |