C# 如何在asp net core 2.2中间件中多次读取请求正文?

C# 如何在asp net core 2.2中间件中多次读取请求正文?,c#,middleware,asp.net-core-2.2,C#,Middleware,Asp.net Core 2.2,我试过这个: 这是: 但没有起作用。 我这样读请求体: app.Use(async (context, next) => { var requestBody = await ReadStream(context.Request.Body); var requestPath = context.Request.Path.ToString(); //Do some thing await next.Invoke(); var responseStat

我试过这个: 这是: 但没有起作用。 我这样读请求体:

app.Use(async (context, next) =>
{
    var requestBody = await ReadStream(context.Request.Body);
    var requestPath = context.Request.Path.ToString();
    //Do some thing

    await next.Invoke();

    var responseStatusCode = context.Response.StatusCode;
    //Do some other thing
});

private async Task<string> ReadStream(Stream stream)
{
    using (var streamReader = new StreamReader(stream))
    {
        var result = await streamReader.ReadToEndAsync();

        return result;
    }
}
app.Use(async (context, next) =>
{
    context.Request.EnableRewind();
    var stream = context.Request.Body;

    using (var reader = new StreamReader(stream))
    {
        var requestBodyAsString = await reader.ReadToEndAsync();

        if (stream.CanSeek)
            stream.Seek(0, SeekOrigin.Begin);

        //Do some thing

        await next.Invoke();

        var responseStatusCode = context.Response.StatusCode;
        //Do some other thing
    }
});
app.Use(异步(上下文,下一步)=>
{
var requestBody=await ReadStream(context.Request.Body);
var requestPath=context.Request.Path.ToString();
//做点什么
等待next.Invoke();
var responseStatusCode=context.Response.StatusCode;
//做些别的事
});
专用异步任务读取流(流)
{
使用(var streamReader=新streamReader(stream))
{
var result=wait streamReader.ReadToEndAsync();
返回结果;
}
}

在controller中,我得到了“disposed object”或“empty stream”。

这可能是因为
StreamReader周围使用了
语句。使用dispose处理
StreamReader
,它在底层流上调用dispose。有关更多详细信息,请参见答案。您可以尝试在
wait next.Invoke()之后保留引用并处理
StreamReader
完成。

经过更多的努力和使用 “context.Request.EnableRewind()” 它最终是这样工作的:

app.Use(async (context, next) =>
{
    var requestBody = await ReadStream(context.Request.Body);
    var requestPath = context.Request.Path.ToString();
    //Do some thing

    await next.Invoke();

    var responseStatusCode = context.Response.StatusCode;
    //Do some other thing
});

private async Task<string> ReadStream(Stream stream)
{
    using (var streamReader = new StreamReader(stream))
    {
        var result = await streamReader.ReadToEndAsync();

        return result;
    }
}
app.Use(async (context, next) =>
{
    context.Request.EnableRewind();
    var stream = context.Request.Body;

    using (var reader = new StreamReader(stream))
    {
        var requestBodyAsString = await reader.ReadToEndAsync();

        if (stream.CanSeek)
            stream.Seek(0, SeekOrigin.Begin);

        //Do some thing

        await next.Invoke();

        var responseStatusCode = context.Response.StatusCode;
        //Do some other thing
    }
});
当第二次读取流时,流指针被设置到最后一个位置。您应该尝试将其移回零位,以便从头开始再次读取

使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用Microsoft.AspNetCore.Builder;
使用Microsoft.AspNetCore.Http;
使用Microsoft.AspNetCore.WebUtilities;
使用Microsoft.Extensions.Logging;
使用Newtonsoft.Json;
使用Newtonsoft.Json.Linq;
使用NLog;
命名空间测试\u middleware.middleware
{
//您可能需要在项目中安装Microsoft.AspNetCore.Http.Abstractions包
公共类日志中间件
{
private readonly RequestDelegate\u next;
专用只读ILogger\u记录器;
公共日志中间件(RequestDelegate next,ILogger logger)
{
_下一个=下一个;
_记录器=记录器;
}
公共异步任务InvokeAsync(HttpContext HttpContext)
{
var HttpContextBody=httpContext.Request.Body;
字符串requestBody=“”;
httpContext.Request.EnableBuffering();
//让主体保持打开状态,以便下一个中间件可以读取它。
使用(var reader=newstreamreader)(
httpContext.Request.Body,
编码:encoding.UTF8,
从字节顺序标记检测到编码:false,
缓冲区大小:-1,
(开:对)
{
var body=wait reader.ReadToEndAsync();
//对身体做一些处理…
//重置请求主体流位置,以便下一个中间件可以读取它
httpContext.Request.Body.Position=0;
}
_LogDebug(“中间件1 body=“+requestBody”);
wait_next.Invoke(httpContext);
}
}
//用于将中间件添加到HTTP请求管道的扩展方法。
公共静态类日志MiddleWareExtensions
{
公共静态IApplicationBuilder UseLoggingMiddleware(此IApplicationBuilder)
{
返回builder.UseMiddleware();
}
}
}
有关更多信息,请参阅以下链接:


.netcore 3.1版@HoussamNasser的上述答案。我创建了一个可重用的函数来读取请求体。请注意更改:
HttpRequestRewindExtensions.EnableBuffering(请求)
。启用缓冲现在是类的一部分

公共异步任务GetRequestBodyAsync(HttpRequest请求) { JObject objRequestBody=新JObject(); //要点:确保可以多次读取requestBody。 HttpRequestWrindExtensions.EnableBuffering(请求); //重要提示:保持主体打开,以便下一个中间件可以读取它。 使用(StreamReader=新StreamReader)( 请求机构, Encoding.UTF8, 从字节顺序标记检测到编码:false, (开:对) { string strRequestBody=wait reader.ReadToEndAsync(); objRequestBody=Serialized.Deserialize(strRequestBody); //重要提示:重置请求主体流位置,以便下一个中间件可以读取它 request.Body.Position=0; } 返回objRequestBody; }
此函数将返回一个JObject,可用于读取请求主体对象的属性。Serialized是用于序列化和反序列化的自定义扩展


在中间件中,您可以在构造函数中注入
IHttpContextAccessor httpContextAccessor
。然后访问请求对象,如
HttpRequest Request=\u httpContextAccessor.HttpContext.Request。最后,可以调用可重用的函数,如
GetRequestBodyAsync(request)

我一直在努力解决这个问题,.net core 3.1已经有了突破性的更改,.net core 3.1中不再提供“context.request.EnableRewind();”,更多有用的提示

asp.net mvc api.net core 3.1(startup.cs)中的工作代码


说得好,我在next.Invoke()之后处理了streamReader,它成功了。您在.NETCore3中尝试过这个吗?我试过了,但它似乎不起作用了。是的,它在dotnet core 3.0中不起作用。还有另一种方法:使用Microsoft.AspNetCore.Http;然后调用“context.Request.enableBuffer()”@JanPaoloGo@AlirezaYavari迁移到.net core 3.0时,我也面临同样的问题。在.NETCore3.0中,我想使用BodyReader管道。我出于日志目的处理了请求正文,但收到验证错误“输入不包含任何JSON令牌。当isFinalBlock为true时,输入应以有效的JSON令牌开头。路径:$|行号:0
            app.Use(async (context, next) =>
        {
            context.Request.EnableBuffering();
            var stream = context.Request.Body;

            using (var reader = new StreamReader(stream))
            {
                var requestBodyAsString = await reader.ReadToEndAsync();

                if (stream.CanSeek)
                    stream.Seek(0, SeekOrigin.Begin);
               
                //some logging and other stuff goes here

                await next.Invoke();

            }
        });