ASP.net MVCコントローラーにIndex
アクションがあります。このアクションは、(特に)行の大きなセットを含むSQLテーブルでカウントを行うプライベートアクションを呼び出します。返された番号はビューバッグプロパティに挿入されます。
public ActionResult Index()
{
// do things
ViewBag.NumberOfRows = NumberOfRows();
return View();
}
private string NumberOfRows()
{
// sql connection and row count
return numberOfRows;
}
これは機能しますが、行数を含めてeverythingが実行されるまで、インデックスページは表示されません。代わりに、プライベート関数がまだ完了していない場合でも、Index
アクションをすぐに完了します。カウントが完了したら、ビューバッグプロパティに値を設定します。今私はこれをやった:
private async Task<string> NumberOfRows()
{
SqlConnection connection = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand();
SqlDataReader reader;
cmd.CommandText = "SELECT SUM (row_count) FROM sys.dm_db_partition_stats WHERE object_id=OBJECT_ID('aTable') AND (index_id=0 or index_id=1)";
cmd.CommandType = CommandType.Text;
cmd.Connection = connection;
await connection.OpenAsync();
reader = await cmd.ExecuteReaderAsync();
string numberOfRows = "N/A";
while (await reader.ReadAsync())
{
numberOfRows = reader.GetInt64(0).ToString();
}
connection.Close();
return numberOfRows ;
}
public async Task<ActionResult> Index(FormCollection form){
// do things;
ViewBag.NumberOfRows = await NumberOfRows();
return View();
}
これは機能します。しかし、これは本当に非同期なのでしょうか?私は何かを逃していますか、これを行う他の方法はありますか?
async
呼び出しですが、ここで理解しておくべき重要なことの1つは、コントローラーのアクションをasync
にした場合です。スレッド(asp.netスレッドプールの)スレッドは、要求を処理してスレッドプール(asp .netリクエストスレッドプール)。
つまり、adプールのスレッドを解放して、より多くの要求を処理します(非同期コントローラーアクションは、より多くの要求を処理するのに役立つだけであり、処理時間を短縮することを意味するのではなく、サーバーの応答性を高めるだけです)。 async/awaitでの操作が完了すると、要求スレッドプールからの新しいスレッドがさらに処理を行います。
実際の非同期ページが必要な場合、つまりページの応答性を高めたい場合は、jQueryの.ajax()
関数を使用するか、Asp.net MVCで利用可能なajax拡張機能を使用することをお勧めします。
これは機能します。しかし、これは本当に非同期なのでしょうか?
データベースにクエリを実行すると(IOバインドされた操作))、ASP.NET Thread-Poolスレッドを使用して、クエリが完了するまでブロックする代わりに解放するので、非同期です。 。
非同期は"この要求を呼び出し元に返し、後で実行を終了します"を意味するわけではありません。これは、HTTP要求/応答プロトコルを壊しません。あなたが望むものは非同期では達成されません。
リクエストをすぐに完了する場合は、バックグラウンドスレッドでリクエストをキューに入れ、操作が完了したらデータをクライアント側にプッシュする必要があります。
非同期の代わりに、Task.Runを使用します。
Task.Run(() => MethodToExecuteInBackground(methodParameters)).ConfigureAwait(false).GetAwaiter();
コントローラのIndexメソッドからasync修飾子を削除する必要もあります。
これで、コントローラーメソッドは、MethodToExecuteInBackground
がオフになり、バックグラウンドでいくつかの作業を行う間、すぐに戻ります。
これにより、MethodToExecuteInBackground
が終了するまでスレッドプールのスレッドが拘束されることに注意してください。