如何在 netcore 3 中多次读取 http 请求正文?

w2o*_*ves 5 c# asp.net-core asp.net-core-3.0

我有一个 netcore 3 API 应用程序,它记录传入的请求,然后将其传递给控制器​​操作。

我的代码如下所示:

public RequestLoggingHandler(IHttpContextAccessor httpContextAccessor)
{
    _httpContextAccessor = httpContextAccessor;
}


protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RequestLoggingRequirement requirement)
{
    try
    {
        var httpContext = _httpContextAccessor.HttpContext;
        var request = httpContext.Request;

        _repository = (ICleanupOrderRepository)httpContext.RequestServices.GetService(typeof(ICleanupOrderRepository));
        _cache = (IMemoryCache)httpContext.RequestServices.GetService(typeof(IMemoryCache));

        httpContext.Items["requestId"] = SaveRequest(request);

        context.Succeed(requirement);

        return Task.CompletedTask;
    }
    catch (Exception ex)
    {

        throw ex;
    }
}

private int SaveRequest(HttpRequest request)
{
    try
    {
        // Allows using several time the stream in ASP.Net Core
        var buffer = new byte[Convert.ToInt32(request.ContentLength)];
       request.Body.ReadAsync(buffer, 0, buffer.Length);

        var requestContent = Encoding.UTF8.GetString(buffer);
        var requestId = _repository.SaveRawHandlerRequest($"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {requestContent}");

        return requestId;
    }
    catch (Exception ex)
    {

        throw ex;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,当此请求传递给控制器​​时,请求正文为空。

以前在 Core2.x 中你可以这样做

request.EnableRewind();
Run Code Online (Sandbox Code Playgroud)

我的理解是这现在被替换为

httpContext.Request.EnableBuffering();
Run Code Online (Sandbox Code Playgroud)

然而,即使有

httpContext.Request.EnableBuffering();
Run Code Online (Sandbox Code Playgroud)

一旦请求正文被读取,请求正文仍然为空。

我怎样才能解决这个问题?

Ren*_*ena 6

这是github 上的一个已知问题

临时解决方法是在调用 EnableBuffering 后立即拉出主体,然后将流倒回 0 并且不处理它:

public class RequestLoggingHandler : AuthorizationHandler<RequestLoggingRequirement>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    public RequestLoggingHandler(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RequestLoggingRequirement requirement)
    {
        try
        {
            var httpContext = _httpContextAccessor.HttpContext;
            var request = httpContext.Request;
            request.EnableBuffering();

            httpContext.Items["requestId"] = SaveRequest(request);
            context.Succeed(requirement);

            return Task.CompletedTask;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
    private int SaveRequest(HttpRequest request)
    {
        try
        {
            // Allows using several time the stream in ASP.Net Core
            var buffer = new byte[Convert.ToInt32(request.ContentLength)];
            request.Body.ReadAsync(buffer, 0, buffer.Length);
            var requestContent = Encoding.UTF8.GetString(buffer);
            var requestId = _repository.SaveRawHandlerRequest($"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {requestContent}");

            request.Body.Position = 0;//rewinding the stream to 0
            return requestId;
        }
        catch (Exception ex)
        {

            throw ex;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)