我正在嘗試在我的 Web API 啟動時執行邏輯,此代碼也將是異步的。
我想過,IStartupFilter但這是同步,這是一個問題。StartUp.Configure()也不是一個選項,同步。
我已經想到了,IHostedService但這會在應用程式完成加載和請求之前運行。
還有其他方法可以做到這一點嗎?
uj5u.com熱心網友回復:
您可能沒有意識到,運行應用程式有兩部分,當您呼叫IHost.Run/時,這些部分默認是隱藏的IHost.RunAsync。
基本上,這個:
var host = CreateHostBuilder(args).Build();
await host.RunAsync();
相當于:
var host = CreateHostBuilder(args).Build();
await host.StartAsync();
await host.WaitForShutdownAsync();
當StartAsync回傳時,應用程式已經開始,準備消費的要求,所以你可能想這樣做:
var host = CreateHostBuilder(args).Build();
await host.StartAsync();
await PerformSomeWorkAfterStartupAsync();
await host.WaitForShutdownAsync();
uj5u.com熱心網友回復:
實作IStartupTask、注冊StartupTaskRunner并 YourStartupTask在 DI 中:
services
.AddStartupTasksRunner()
.AddStartupTask<YourStartupTask>();
這里是基于Andrew's Lock帖子的代碼:
public interface IAsyncStartupTask
{
Task OnStartupAsync(CancellationToken cancellationToken);
}
internal class StartupTasksRunner : IHostedService
{
private readonly IEnumerable<IAsyncStartupTask> _startupTasks;
private readonly IHostApplicationLifetime _applicationLifetime;
private readonly SemaphoreSlim _semaphore;
public StartupTasksRunner(IEnumerable<IAsyncStartupTask> startupTasks, IHostApplicationLifetime applicationLifetime)
{
_startupTasks = startupTasks;
_applicationLifetime = applicationLifetime;
_semaphore = new SemaphoreSlim(0);
applicationLifetime.ApplicationStarted.Register(() => _semaphore.Release());
}
public async Task StartAsync(CancellationToken cancellationToken)
{
// wait for ApplicationStarted event to execute when app is listening to web requests
// await _semaphore.WaitAsync(cancellationToken);
foreach (var task in _startupTasks)
{
try
{
await task.OnStartupAsync(cancellationToken).ConfigureAwait(false);
}
catch
{
// stop the application if failing startup task if fatal
//_applicationLifetime.StopApplication();
throw;
}
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddStartupTasksRunner(this IServiceCollection services)
{
return services.AddHostedService<StartupTasksRunner>();
}
public static IServiceCollection AddStartupTask<TStartupTask>(this IServiceCollection services)
where TStartupTask : class, IAsyncStartupTask
{
return services.AddSingleton<IAsyncStartupTask, TStartupTask>();
}
}
說明
該應用程式的啟動順序是:
- 開始
HostedService的 - 啟動 Kesterl 服務器
- 火災
ApplicationStarted事件
If you want to run your startup task before HostedServices started you need to make sure StartupTasksRunner registered before any other HostedService (they are started in registration order).
If you want to run your startup task after all HostedServices started but before application starts to receive web requests make sure you are registering StartupTasksRunner after any other HostedService.
If you want to run your startup task after Kestrel Server is started uncomment // await _semaphore.WaitAsync(cancellationToken); line. Be aware that it may run concurrently with web requests handling.
Also be aware that exceptions thrown by IHostedService.StartAsync method will be swallowed by framework. So if successful execution of startup tasks is necessary for your application uncomment // _applicationLifetime.StopApplication();
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/335855.html
標籤:C# asp.net核心 asp.net-core-5.0
