ASP.Net Coreにページをロードするときに非同期タスクを実行しようとしています。つまり、ユーザーがページにルーティングするとすぐにタスクを実行しますが、タスクが完了する前にページを表示します。 ASP.Netコアでは、ミドルウェアを使用してそのようなタスクを実行しているようです。そこで、_Startup.cs
_に以下を追加しようとしました
_public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
// Other configurations here
app.Use(async (context, next) =>
{
if (context.Request.Path.Value.Contains("PageWithAsyncTask"))
{
var serviceWithAsyncTask = serviceProvider.GetService<IMyService>();
await serviceWithAsyncTask .DoAsync();
}
await next.Invoke();
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
_
上記の問題は、DoAsync
が完了するまでnext.Invoke()
を呼び出さないため、DoAsync
が完了するまでページの読み込みに遅延が発生することです。 DoAsync
を実行した直後にnext.Invoke()
が呼び出されるように、上記を正しく実装するにはどうすればよいですか?
ASP.NETは、バックグラウンドタスク用に設計されていません。私は強く信頼できるキュー(Azureキュー/ MSMQ)を使用して、Azure Functions/WebJobs/Worker Roles/Win32サービスなどの適切なアーキテクチャを使用することをお勧めします/など)ASP.NETアプリがそのサービスと通信するため。
ただし、本当にしたい場合、およびリスクを受け入れる意思がある場合(具体的には、作業が中止される可能性がある場合)、-を使用できます。 IApplicationLifetime
。
ASP.NET Core 2では、IHostedServiceはバックグラウンドタスクを実行するように設計されています。 IHostedServiceをシングルトンとして登録すると、起動時に自動的に開始されます。
Asp.Netコア2.1はバックグラウンドタスクを使用するため、 IHostedService
基本クラスから派生してBackgroundService
を実装すると非常に便利です。これが ここ から取られたサンプルです:
public class MyServiceA : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
Console.WriteLine("MyServiceA is starting.");
stoppingToken.Register(() => Console.WriteLine("MyServiceA is stopping."));
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine("MyServiceA is doing background work.");
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
Console.WriteLine("MyServiceA background task is stopping.");
}
}
次に、それをStartup.ConfigureServices
に登録します。
services.AddSingleton<IHostedService, MyServiceA>();
また、Stephen Clearyが指摘したように、Asp.Net
アプリケーションはバックグラウンドタスクに最適な場所ではない可能性があります(たとえば、アプリがIISでホストされている場合)、アプリプールのリサイクルのためにシャットダウンされる可能性があります)。一部のシナリオでは、非常にうまく適用できます。
の代わりに
_await serviceWithAsyncTask .DoAsync();
_
あなたが使うことができます
_ ThreadPool.QueueUserWorkItem(delegate {
SomeMethod();
});
_
このアプローチでは、スレッドプールから追加のスレッドが使用されます。これはもちろん、コードをメインスレッド以外のスレッドで実行する場合の要件です:-)
このブロックの後に配置されたコードはすべてすぐに実行されます。また、Webサーバープロセス(ケストラル)がIISまたは使用しているリバースプロキシによってリサイクルされる場合、バックグラウンドワーカーはすぐに中止されるため、バックグラウンドワーカーは防御的に作成する必要があります。これを念頭に置いてください。
また、SomeMethod()
自体はasync
メソッドではないことに注意してください。ただし、バックグラウンドスレッドから呼び出されているため、非同期で実行されています(つまり、メインスレッドから独立しています)。
バックグラウンド処理を管理するためのHangFireを見てください。NetCoreでうまく機能します: https://www.hangfire.io/