15

次のMVCアクションがあります。

public async Task<JsonResult> DoSomeLongRunningOperation()
{
    return await Task.Run(() =>
    {
        //Do a lot of long running stuff
        //The underlying framework uses the HttpContext.Current.User.Identity.Name so the user is passed on the messagebus.
    }
}

タスクでは、HttpContextがnullになります。私たちは多くのトリックを行いましたが、HttpContextが新しいスレッドで常に利用可能であることを保証するものは何もありません。

非同期タスク内でHttpContextを使用するためのソリューションはありますか?

IocContainerに、ユーザー名をフレームワークに渡す次のオブジェクトを登録しました。

public class HttpContextUserIdentityName : ICredentials
{
    public string Name
    {
        get { return HttpContext.Current.User.Identity.Name; }
    }
}

このコードは、データベースに永続化する前に多くの場所で呼び出されます。

Webリクエストを開始したユーザーのユーザー名を取得する別の方法が必要であるか、HttpContextがnullである問題を修正する必要があります。

データベースへの永続化はタスクで発生するため、タスクに入る前にHttpContextにアクセスできません。

また、別のICredentialsサービスオブジェクトを実装できるように、ユーザー名を一時的に永続化する安全な方法を考えることもできません。

4

3 に答える 3

5

Task.RunASP.NET メソッドで使用することはほとんどありません。

最もクリーンな解決策 (ただし、最もうまくいく) はasync、他のレイヤーに互換性のあるインターフェイスを実装することだと思います。

public async Task<JsonResult> DoSomeLongRunningOperation()
{
  //Do a lot of long running stuff
  var intermediateResult = await DoLongRunningStuff();
  return await DetermineFinalResult(intermediateResult);
}
于 2012-12-06T17:46:30.620 に答える
4

新しいスレッドを開始する前に、現在のコンテキストから必要な情報を取得する必要があります。この場合、次のようなものを追加します。

string username = HttpContext.Current.User.Username;

前にTask.Run、それを他のスレッドの内部で使用します。

await余談ですが、現状では、このタスクに理由はありません。タスクを直接返すだけで、メソッドを としてマークすることはできませんAsync

オブジェクトにアクセスする必要がある場合はResponse、おそらく長時間実行されている操作の結果を利用するTask.Runため、後でアクセスTask.Runする必要があります(ただし、タスクがawaited であることを確認してください)。これをやってしまうと、前の段落で提案したことができなくなります。

于 2012-12-06T16:44:08.393 に答える
3

作業を実行するスレッドのスタック上にそのオブジェクトの新しいインスタンスを作成する必要があるため、HttpContext への参照を状態オブジェクトとして渡してみます。Task.Run を使用する代わりに、

return await Task.Factory.StartNew((ctx) => 
{
    var context = (HttpContext)ctx;
   //Do stuff
}, httpContextObject);

Task.Run と Task.Factory.StartNew がすぐに返されるため、asp.net は、スレッドが既に破棄されたオブジェクトを操作している間、要求を処理しているワーカー スレッドのイベント ライフサイクルを続行します。

于 2012-12-06T18:06:44.483 に答える