23

次の ASP.NET Web API 委任ハンドラーを検討してください。

public class MyHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var guid = Guid.NewGuid();
        HttpContext.Current.Items["foo"] = guid;

        // An Async operation
        var result = await base.SendAsync(request, cancellationToken);

        //All code from this point is not gauranteed to run on the same thread that started the handler

        var restoredGuid = (Guid)HttpContext.Current.Items["foo"];

        //Is this gauranteed to be true
        var areTheSame = guid == restoredGuid;

        return result;
    }
}

上記の例は委任ハンドラーにあります。私が修正しようとしているのと同じ問題が、コントローラー、ビジネス オブジェクトなどに適用されます。

私は最終的に、HTTP リクエストごとにさまざまなオブジェクト間で単純なメモリ内共有状態を提供しようとしています。

非同期操作中に理解しているように、最初に操作を実行していた ASP.NET スレッドはスレッド プールに返され、非同期操作が完了した後、別のスレッドを使用して要求を終了できます。

HttpContext.Current.Itemsコレクションに影響はありますか?コレクションにあった項目はItems、要求が再開されたときにそこにあることが保証されていますか?

  1. 私はHttpContext.Current、私が完全に同意する理由で、最近、より広いコミュニティによって使用がしばしば眉をひそめていることを認識しています.

  2. このデータをコレクションに保存することは、Request.Itemsこの問題の解決には適していません。私の同僚は、設計上の決定が不十分なために静的を必要とするからです。

どうもありがとう

4

2 に答える 2

27

私が理解しているように、非同期操作中に、最初に操作を実行していた ASP.NET スレッドがスレッド プールに返され、非同期操作が完了した後、別のスレッドを使用して要求を完了することができます。

それは正しいです。asyncしかし、ASP.NET について少し話しましょう。

async.NET 4.5 が必要です。さらに、ASP.NET 4.5 ではサーバー側に "quirks モード" が導入されているため、SynchronizationContextquirkをオフにする必要があります。これを行うには、 を に設定httpRuntime.targetFrameworkする4.5 、 の値を使用appSettingsします。aspnet:UseTaskFriendlySynchronizationContexttrue

web.config にこれらのエントリのいずれも含まれていない場合、の動作asyncは未定義です。詳細については、この投稿を参照してください。targetFramework設定を使用して、発生した問題を修正することをお勧めします。

これは HttpContext.Current.Items コレクションに影響しますか? 要求が再開されたときに、Items コレクションにあったアイテムがそこにあることが保証されていますか?

は、ポイントAspNetSynchronizationContext全体で現在の要求コンテキストを保持します。awaitこれにはHttpContext.Current( 、 などを含むItems)が含まれUserます。

もう 1 つの可能性はCallContext.Logical[Get|Set]Dataで、これもポイント間を流れawaitます。これは、 にコードを依存させたくない場合に便利ですがHttpContext、オーバーヘッドがわずかに大きくなります。

async数週間前の ThatConferenceで、サーバー側について講演しました。スライド、特に Context と Thread-Local State を扱っているスライドが役立つことがあります。

于 2013-08-27T12:29:25.350 に答える
6

要するに、通常はそうすべきです。whichを使用していない限りConfigureAwait(false)、継続がコンテキストを流れないという副作用を引き起こす可能性があります。

または、この設定をアプリに追加してみてください。

<appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>

アップデート

ノート!!最初に私はfalseを入れました。しかし、コンテキストが流れるように、それは真でなければなりません。

于 2013-08-27T09:00:51.960 に答える