11

並行性の高い Web アプリケーションを構築しており、最近では非同期プログラミングを広範囲に使用し始めています (TPL とasync/を使用await)。

アプリが REST API (ASP.NET Web API の上に構築) を介して相互に通信する分散環境があります。ある特定のアプリでは、DelegatingHandler呼び出し後base.SendAsync(つまり、応答の計算後) に応答をファイルに記録します。応答の基本情報 (ステータス コード、ヘッダー、およびコンテンツ) をログに含めます。

public static string SerializeResponse(HttpResponseMessage response)
{
    var builder = new StringBuilder();
    var content = ReadContentAsString(response.Content);

    builder.AppendFormat("HTTP/{0} {1:d} {1}", response.Version.ToString(2), response.StatusCode);
    builder.AppendLine();
    builder.Append(response.Headers);

    if (!string.IsNullOrWhiteSpace(content))
    {
        builder.Append(response.Content.Headers);

        builder.AppendLine();
        builder.AppendLine(Beautified(content));
    }

    return builder.ToString();
}

private static string ReadContentAsString(HttpContent content)
{
    return content == null ? null : content.ReadAsStringAsync().Result;
}

問題は次のとおりです。コードがcontent.ReadAsStringAsync().Resultサーバーの負荷が高い状態に達すると、リクエストが IIS でハングすることがあります。実行すると、応答が返されることがありますが、IIS で応答がないかのようにハングアップするか、返されない場合もあります。

また、 を使用してコンテンツを読み取ってReadAsByteArrayAsyncから に変換しようとしましたStringが、うまくいきませんでした。

全体で async を使用するようにコードを変換すると、さらに奇妙な結果が得られます。

public static async Task<string> SerializeResponseAsync(HttpResponseMessage response)
{
    var builder = new StringBuilder();
    var content = await ReadContentAsStringAsync(response.Content);

    builder.AppendFormat("HTTP/{0} {1:d} {1}", response.Version.ToString(2), response.StatusCode);
    builder.AppendLine();
    builder.Append(response.Headers);

    if (!string.IsNullOrWhiteSpace(content))
    {
        builder.Append(response.Content.Headers);

        builder.AppendLine();
        builder.AppendLine(Beautified(content));
    }

    return builder.ToString();
}

private static Task<string> ReadContentAsStringAsync(HttpContent content)
{
    return content == null ? Task.FromResult<string>(null) : content.ReadAsStringAsync();
}

HttpContext.Currentへの呼び出し後は null になりcontent.ReadAsStringAsync()その後のすべてのリクエストでも null のままです。信じられないことだとは思いますが、これが実際に起こっていることだと理解するには、3 人の同僚の存在と時間がかかりました。

これはある種の予想される動作ですか?ここで何か間違ったことをしていますか?

4

2 に答える 2

10

この問題がありました。まだ完全にはテストしていませんが、ReadAsStringAsync の代わりに CopyToAsync を使用すると問題が解決するようです。

var ms = new MemoryStream();
await response.Content.CopyToAsync(ms);
ms.Seek(0, SeekOrigin.Begin);

var sr = new StreamReader(ms);
responseContent = sr.ReadToEnd();
于 2014-12-04T18:07:26.850 に答える