18

当尝试在控制器中的操作中处理对象时,它偶尔似乎为空。我发现这ReadAsStringAsync()SendAsync()由于DelegatingHandler. 问题在于内容。当我的客户端发送内容主体并在记录器中读取它时,Controller Action Invoker 永远不会读取它(或者可能在JsonFormatter. 我怀疑后续调用Content.ReadAsStringAsync()不会引发异常,但也不会返回预期的内容主体(返回一些信息,说明异步读取已完成)。

但是我的问题仍然存在,因为我想读取[FromBody]动作中的参数,并且当 RaceConditionContent.ReadStringAsyncDelegatingHandler. 但是,当JsonFormatter赢得它时,我得到了对象,但这很少见(仅在服务启动时)。

这是我的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 中,正文内容被视为只能读取一次的只进流。

您可以尝试使用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;
}

@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 回答