待機後にHttpContext.Currentがnullになるのはなぜですか?


89

私は次のテストWebAPIコードを持っています。本番環境ではWebAPIを使用していませんが、この質問について話し合ったために作成しました。WebAPI非同期の質問

とにかく、これが問題のあるWebAPIメソッドです。

public async Task<string> Get(int id)
{
    var x = HttpContext.Current;
    if (x == null)
    {
        // not thrown
        throw new ArgumentException("HttpContext.Current is null");
    }

    await Task.Run(() => { Task.Delay(500); id = 3; });

    x = HttpContext.Current;
    if (x == null)
    {
        // thrown
        throw new ArgumentException("HttpContext.Current is null");
    }

    return "value";
}

私はこれまで、2番目の例外が予想されると信じていawaitました。これは、完了すると、別のスレッドで発生する可能性が高くHttpContext.Current、thread-static変数が適切な値に解決されなくなるためです。さて、同期コンテキストに基づいて、待機後に実際には同じスレッドに戻ることを強制される可能性がありますが、テストでは特別なことは何もしていません。これは、の単純で素朴な使用法ですawait

別の質問のコメントでHttpContext.Current、待ってから解決する必要があると言われました。同じことを示すこの質問にはさらに別のコメントがあります。では、何が本当ですか?それは解決する必要がありますか?いいえと思いますが、これについては信頼できる答えが必要です。なぜならasync、それawaitは十分に新しいので、決定的なものを見つけることができないからです。

TL; DR:HttpContext.Current潜在的nullawait


3
あなたの質問は不明確です-あなたはあなたが何が起こると期待していたかを言いました、そしてコメントはそれが起こっていることを示しています...それであなたを混乱させるもの何ですか?
Jon Skeet

@ user2674389、これは誤解を招く恐れがあります。それAspNetSynchronizationContextHttpContext、ではなく、世話をすることawaitです。さらに、の継続コールバックはawait、Web API実行モデルの別のスレッドで発生する可能性があります(おそらく発生する可能性があります)。
noseratio 2013

簡潔な質問をするために編集
welegan 2013

1
@JoepBeusenbergある特定のWebスタックのHTTPリクエストのコンテキスト内で実行されているアセンブリから呼び出された場合にのみ機能する個別のアセンブリを作成すると、テスト、メンテナンス、および再利用が困難になる可能性があります。
ダレルミラー

1
@DarrelMillerまったく逆です。ビジネスロジックを実際のWebプロジェクトから分離しました。依存性注入を使用して、ビジネスロジックの上にwebapi対応ライブラリを追加できます。しかし、このライブラリは、ビジネスロジックが.ConfigureAwait(false)どこかで実行されたときに壊れます。ビジネス層はWebに対応していないため、ビジネス層を介して明示的に渡される要求やコントローラーはありません。これは、たとえば、ビジネスロジックがジェネリックを書き込むときに要求の詳細を挿入できるロギングモジュールの場合に役立ちますTraceInformation
Joep Beusenberg 2017

回答:


148

ASP.NET 4.5アプリケーションを作成し、4.5をターゲットにしていることを確認してください。asyncそしてawaitあなたは4.5上で実行されていない限りASP.NETでの未定義の動作を持っているし、新しい「タスクに優しい」同期コンテキストを使用しています。

特に、これは次のいずれかを行う必要があることを意味します。

  • 設定するhttpRuntime.targetFrameworkには4.5、または
  • appSettings、に設定aspnet:UseTaskFriendlySynchronizationContexttrueます。

詳細については、こちらをご覧ください


2
新しいASP.NET4.5 WebAPIプロジェクトを作成し、コードをコピーして貼り付け、テストを行いました。それは私にとって完璧に機能しました(どちらの例外もスローされませんでした)。4.5を実行してターゲットにしていることを再確認してください。
スティーブンクリアリー2013

3
Target Framework:.NET Framework4.5が設定されています。私はあなたに何を言うべきかわかりません、それは私のローカルマシンでは間違いなくヌルです。
welegan 2013

24
<httpRuntime targetFramework="4.5" />明確にするため、おかげでそれを解決するものです。
welegan 2013

1
@Vince:4.5.1は正常に動作するはずです。targetFramework4.5.1または4.5に設定する必要があるかどうかはわかりませんが、4.5.1での非同期は正常に機能するはずです。
スティーブンクリアリー2015

1
独自のマネージハンドラーを作成した場合はどうなりますか?これらのアイテムをweb.configに追加した後でも、そこにHttpContext.Current = nullが表示され続けます。
Brain2000 2016年

28

@StephenClearyが正しく指摘しているように、web.configでこれが必要です。

<httpRuntime targetFramework="4.5" />

これを最初にトラブルシューティングしたとき、上記をソリューション全体で検索し、すべてのWebプロジェクトに存在することを確認し、すぐに原因として却下しました。最終的に、これらの検索結果を完全なコンテキストで見ることになりました。

<!--
  For a description of web.config changes for .NET 4.5 see http://go.microsoft.com/fwlink/?LinkId=235367.

  The following attributes can be set on the <httpRuntime> tag.
    <system.Web>
      <httpRuntime targetFramework="4.5" />
    </system.Web>
-->

ドー。

レッスン:Webプロジェクトを4.5にアップグレードする場合でも、その設定を手動で行う必要があります。


22
もう1つの落とし穴は、これが<compilation targetFramework "4.5" />とは異なることです
Andrew

3

私のテストに欠陥がありますか、それともここで欠落しているweb.config要素があり、待機後にHttpContext.Currentが正しく解決されますか?

テストに欠陥はなく、待機後にHttpContext.Currentがnullになることはありません。これは、ASP.NET Web APIで待機すると、この待機に続くコードに、待機前に存在していた正しいHttpContextが確実に渡されるためです。


WebAPIの同じ継続スレッドについて確信がありますか?別のスレッドの場合を扱いました。
noseratio 2013

4
ASP.NETは、任意のスレッドプールスレッドで再開しますが、要求コンテキストは正しいです。
Stephen Cleary 2013

2
はい、その通りです。スレッドは同じではないかもしれませんが、HttpContext.Currentは待機前と同じになります。質問を更新しました。
ダリンディミトロフ

4
コードで待機した後、HttpContext.Currentがnullになり、.net4.6.1をターゲットにしています。
Triynko 2018年

1
私にとってHttpContext.Currentはawait関数の前にnullです
JobaDiniz

2

私は最近この問題に遭遇しました。Stephenが指摘したように、ターゲットフレームワークを明示的に設定しないと、この問題が発生する可能性があります。

私の場合、Web APIはバージョン4.6.2に移行されましたが、ランタイムターゲットフレームワークがWeb構成で指定されなかったため、基本的にこれは<system.web>タグ内にありませんでした。

実行しているフレームワークのバージョンに疑問がある場合は、これが役立つ場合があります。WebAPIメソッドのいずれかに次の行を追加し、ブレークポイントを設定して、実行時に現在ロードされているタイプを確認し、レガシー実装ではないことを確認します。

これが表示されるはずです(AspNetSynchronizationContext):

ここに画像の説明を入力してください

LegazyAspNetSynchronizationContextの代わりに(ターゲットフレームワークを追加する前に見たもの):

ここに画像の説明を入力してください

ソースコード(https://referencesource.microsoft.com/#system.web/LegacyAspNetSynchronizationContext.cs)にアクセスすると、このインターフェイスのレガシー実装には非同期サポートがないことがわかります。

ここに画像の説明を入力してください

私は問題の原因を見つけるために多くの時間を費やし、スティーブンの対応は大いに役立ちました。この回答が問題に関する詳細情報を提供することを願っています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.