从ASP.NET Core 2.0中的中间件获取请求正文在HttpContext中

max*_*pan 6 c# asp.net-core-2.0

我有一个简单的中间件,可获取请求的主体并将其存储在字符串中。它正在读取流,但问题是它不会调用我的控制器,而该控制器在我读取流并抛出错误后立即调用

需要一个非空的请求正文

。下面是我的代码。

  public async Task Invoke(HttpContext httpContext)
            {
                var timer = Stopwatch.StartNew();
                ReadBodyFromHttpContext(httpContext);
                await _next(httpContext);
                timer.Stop();
            }

   private string ReadBodyFromHttpContext(HttpContext httpContext)
        {
           return await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
        }
Run Code Online (Sandbox Code Playgroud)

max*_*pan 9

在捕获 HTTP 请求和/或响应的正文时,这并非易事。在 ASP .NET Core 中,主体是一个流 - 一旦你使用它(在这种情况下用于日志记录),它就消失了,使管道的其余部分变得无用。

参考:http : //www.palador.com/2017/05/24/logging-the-body-of-http-request-and-response-in-asp-net-core/

public async Task Invoke(HttpContext httpContext)
    {
        var timer = Stopwatch.StartNew();
        string bodyAsText = await new StreamReader(httpContext.Request.Body).ReadToEndAsync();
        var injectedRequestStream = new MemoryStream();
        var bytesToWrite = Encoding.UTF8.GetBytes(bodyAsText);
        injectedRequestStream.Write(bytesToWrite, 0, bytesToWrite.Length);
        injectedRequestStream.Seek(0, SeekOrigin.Begin);
        httpContext.Request.Body = injectedRequestStream;
        await _next(httpContext);

        timer.Stop();
    }
Run Code Online (Sandbox Code Playgroud)


mat*_*lto 7

您需要将HttpContext.Request.Body从仅转发内存流转换为可搜索流,如下所示。

//  Enable seeking
context.Request.EnableBuffering();
//  Read the stream as text
var bodyAsText = await new System.IO.StreamReader(context.Request.Body).ReadToEndAsync();
//  Set the position of the stream to 0 to enable rereading
context.Request.Body.Position = 0; 
Run Code Online (Sandbox Code Playgroud)

  • 仅供参考。NetCore 3.1 `Request.Body.Position` 抛出 `NotSupportedException` (2认同)

Szu*_*ubi 7

这里有几件事是至关重要的:

  • 启用缓冲
  • StreamReader 中的最后一个标志leftOpen
  • 重置请求正文流位置(SeekOrigin.Begin)
public void UseMyMiddleware(IApplicationBuilder app)
{
    app.Use(async (context, next) =>
    {
        context.Request.EnableBuffering();

        using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, false, 1024, true))
        {
            var body = await reader.ReadToEndAsync();

            context.Request.Body.Seek(0, SeekOrigin.Begin);
        }

        await next.Invoke();
    });
}
Run Code Online (Sandbox Code Playgroud)