18

コントローラのアクションでオブジェクトを試行すると、散発的にnullのように見えます。ReadAsStringAsync()SendAsync()オーバーライドが原因であることがわかりましたDelegatingHandler。問題はコンテンツにあります。クライアントがコンテンツ本文を送信し、それがロガーで読み取られると、Controller Action Invokerによって読み取られることはありません(またはのどこかにある可能性がありますJsonFormatter)。の後続の呼び出しContent.ReadAsStringAsync()は例外をスローしないが、期待されるコンテンツ本文も返さないのではないかと思います(非同期読み取りが完了したことを示す情報が返されます)。

しかし、アクションでパラメーターを読み取りたいので、私の問題は残ります。RaceConditionがで勝った[FromBody]場合はnullになります。勝ったとき、私はオブジェクトを取得しますが、それはまれです(サービスの起動時のみ)。Content.ReadStringAsyncDelegatingHandlerJsonFormatter

これが私のDelegatingHandlerコードです:

public class LogHandler : DelegatingHandler
{

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var apiRequest = new WebApiUsageRequest(request);
        WriteLog(apiRequest);
        request.Content.ReadAsStringAsync().ContinueWith(t =>
        {
            apiRequest.Content = t.Result;
            WriteLog(apiRequest);
        });

        return base.SendAsync(request, cancellationToken).ContinueWith(task =>
        {
            var apiResponse = new WebApiUsageResponse(task.Result);
            apiResponse.Content = task.Result.Content != null ? task.Result.Content.ReadAsStringAsync().Result : null;
            WriteLog(apiResponse);
            return task.Result;
        });
    }
}

誰かがこの問題の解決策への手がかりを持っていますか?

4

5 に答える 5

9

これは仕様によるものです。ASP.NET Web APIでは、本文のコンテンツは、1回だけ読み取ることができる転送専用ストリームとして扱われます。

ASP.NET Web APIトレースを利用してみてください。ただし、POSTリクエストでテストしていないため、リクエストの本文をトレースする方法/かどうかはわかりません(GETリクエストのパラメーターをトレースしていることは確かです)。あなたはここでもっと読むことができます:

于 2012-08-24T06:34:04.483 に答える
8

ReadAsStreamAsyncメソッドは、本文のコンテンツを返します。

var body = string.Empty;
using (var reader = new StreamReader(request.Content.ReadAsStreamAsync().Result))
{
    reader.BaseStream.Seek(0, SeekOrigin.Begin);
    body = reader.ReadToEnd();
}
于 2015-04-03T09:12:57.783 に答える
6

これが私がやったことです:

public string SafelyReadContent(HttpRequestMessage request)
{
    var stream = request.Content.ReadAsStreamAsync().Result;
    var reader = new StreamReader(stream);
    var result = reader.ReadToEnd();
    stream.Seek(0, SeekOrigin.Begin);

    return result;
}

「using」ブロックを使用するという@pirimogluの回答は、リーダーが破棄されたときに基になるストリームも閉じられたため、機能しませんでした。

于 2016-03-23T15:20:59.430 に答える
4

これは私のために働いた:

using (var stream = new MemoryStream())
{
    var context = (HttpContextBase)Request.Properties["MS_HttpContext"];
    context.Request.InputStream.Seek(0, SeekOrigin.Begin);
    context.Request.InputStream.CopyTo(stream);
    string requestBody = Encoding.UTF8.GetString(stream.ToArray());
}

パラメータオブジェクトのjson表現が返されたので、例外処理とロギングに使用できました。

ここで受け入れられた答えとして見つかりました

于 2016-03-02T17:02:39.643 に答える
2

ただし、SendAsyncで以下のコードを使用すると、正しく機能します

        if (request.Content != null)
        {
            request.Content.ReadAsByteArrayAsync().ContinueWith
                (
                    (task) =>
                    {

                            var xxx = System.Text.UTF8Encoding.UTF8.GetString(task.Result);
                    });
        }
        return base.SendAsync(request, cancellationToken) //than call the base

。。。

于 2013-07-22T18:58:49.703 に答える