私はいくつかの MVC4 非同期コントローラー コードを書いていますが、実行時間の長い 2 つの Web サービスを非同期で呼び出し、2 番目の呼び出しが間違ったスレッドにあるように見えるという問題が発生しています。
コード スニペットは次のとおりです。
public async Task<ActionResult> AmendDetails(Model model)
{
ClientMaintenanceClient clientService = new ClientMaintenanceClient();
UpdateResponse clientResponse = await clientService.GetForUpdateAsync(clientService.CreateRequest(model.Id));
StaticDataEnquiryClient staticService = new StaticDataEnquiryClient();
DataResponse staticResponse = await staticService.GetPayMethodsAsync(staticService.CreateRequest());
...
}
基本的に、CreateRequest() への呼び出しは、HttpContext からセッション ID を検索し、サービスへの呼び出しで使用される形成された WCF 要求オブジェクトを作成します。
ただし、実行時に最初の呼び出しは正常に行われますが、2 番目の非同期呼び出しは HttpContext が null であるため失敗します。これにより、現在別のスレッドにいると思われます。
MVC3 でこれを行ったとき、.Net4.5 より前では、非同期呼び出しから AsyncManager 経由で (EAP を使用して) 戻るときにスレッドを手動で同期する必要がありましたが、TAP でそれを行う必要がなくなったと思いました。
以下のコード スニペットを使用してコードを並行して実行すると、問題は解決します。
public async Task<ActionResult> AmendDetails(Model model)
{
ClientMaintenanceClient clientService = new ClientMaintenanceClient();
var clientTask = clientService.GetForUpdateAsync(clientService.CreateRequest(model.Id));
StaticDataEnquiryClient staticService = new StaticDataEnquiryClient();
var staticTask = staticService.GetPayMethodsAsync(staticService.CreateRequest());
await Task.WhenAll(clientTask,staticTask);
UpdateResponse clientResponse = await clientTask;
DataResponse staticResponse = await StaticTask;
...
}
最初のスニペットでは、最初の await がプロセスをバックグラウンド スレッドに移動しているため、2 番目の await に到達するまでに、まだバックグラウンド スレッドにいると想定しています。そのスレッドから取得できないため、HttpContext は null になります。
また、コードの 2 番目のスニペットでは、最初の待機の前にすべての HTTPContext ルックアップを行っていると想定しているため、バックグラウンド スレッドから呼び出すことはないため、HTTPContext が null として表示されることはありません。
上記の私の仮定を誰かが確認できますか? コード内の明らかなエラーに目を通したくありません。エラーが戻ってきて、後で噛み付きます!
アップデート:
ここで実行中にスレッドをチェックすることにしました。実際には、最初の待機とは異なるスレッドで 2 番目の待機が発生しているようです。興味深いのは、2 回目の呼び出しでHttpContextが null ではないように見えることです。nullのHttpContext.Currentです。
次の方法でセッションIDにアクセスしています:
HttpContext.Current.Session.SessionId
2番目が待機する前に何かを同期する必要があると思いますが、何がわかりません。