如何在 asp net core 2.2 中间件中多次读取请求体?
How to read request body multiple times in asp net core 2.2 middleware?
我试过这个:
和这个:
https://github.com/aspnet/Mvc/issues/4962
但没有用。
我这样阅读请求正文:
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;
}
}
在控制器中我得到 'disposed object' 或 'empty stream'。
这可能是因为您的 StreamReader
周围的 using
语句。使用 disposes StreamReader
调用底层流上的 dispose 。有关详细信息,请参阅答案 here。您可以尝试保留参考并在 await next.Invoke();
完成后处理 StreamReader
。
经过一番折腾和使用
"context.Request.EnableRewind()"
它终于像这样工作了:
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
}
});
When stream is read second time then the stream pointer is set to the last position. You should try to move it back to position zero to read it again from the beginning.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
namespace Test_Middlewares.Middlewares
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<LoggingMiddleware> _logger;
public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext httpContext)
{
var HttpContextBody = httpContext.Request.Body;
string requestBody = "";
httpContext.Request.EnableBuffering();
// Leave the body open so the next middleware can read it.
using (var reader = new StreamReader(
httpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: -1,
leaveOpen: true))
{
var body = await reader.ReadToEndAsync();
// Do some processing with body…
// Reset the request body stream position so the next middleware can read it
httpContext.Request.Body.Position = 0;
}
_logger.LogDebug("Middleware 1 body =" + requestBody);
await _next.Invoke(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class LoggingMiddlewareExtensions
{
public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LoggingMiddleware>();
}
}
}
有关更多信息,请参阅这些链接:
https://devblogs.microsoft.com/aspnet/re-reading-asp-net-core-request-bodies-with-enablebuffering/
.netcore 3.1 版本的@HoussamNasser 上面的回答。我创建了一个可重用函数来读取请求正文。请注意更改:HttpRequestRewindExtensions.EnableBuffering(request)
。 EnableBuffering 现在是 HttpRequestRewindExtensions class.
的一部分
public async Task<JObject> GetRequestBodyAsync(HttpRequest request)
{
JObject objRequestBody = new JObject();
// IMPORTANT: Ensure the requestBody can be read multiple times.
HttpRequestRewindExtensions.EnableBuffering(request);
// IMPORTANT: Leave the body open so the next middleware can read it.
using (StreamReader reader = new StreamReader(
request.Body,
Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
leaveOpen: true))
{
string strRequestBody = await reader.ReadToEndAsync();
objRequestBody = SerializerExtensions.Deserialize<JObject>(strRequestBody);
// IMPORTANT: Reset the request body stream position so the next middleware can read it
request.Body.Position = 0;
}
return objRequestBody;
}
这个函数将return一个JObject,它可以用来读取Request Body对象的属性。 SerializerExtensions 是我用于序列化和反序列化的自定义扩展。
在中间件中,可以在构造函数中注入IHttpContextAccessor httpContextAccessor
。然后像HttpRequest request = _httpContextAccessor.HttpContext.Request;
一样访问Request对象。最后,可以像GetRequestBodyAsync(request)
一样调用可重用的函数
我一直在努力解决它,.net core 3.1 有重大变化,“context.Request.EnableRewind();”在 .net core 3.1 中不再可用,更多有用的提示 visit here
asp.netmvc api.net core 3.1 (startup.cs)
中的工作代码
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();
}
});
我试过这个:
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;
}
}
在控制器中我得到 'disposed object' 或 'empty stream'。
这可能是因为您的 StreamReader
周围的 using
语句。使用 disposes StreamReader
调用底层流上的 dispose 。有关详细信息,请参阅答案 here。您可以尝试保留参考并在 await next.Invoke();
完成后处理 StreamReader
。
经过一番折腾和使用 "context.Request.EnableRewind()" 它终于像这样工作了:
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
}
});
When stream is read second time then the stream pointer is set to the last position. You should try to move it back to position zero to read it again from the beginning.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
namespace Test_Middlewares.Middlewares
{
// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
public class LoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<LoggingMiddleware> _logger;
public LoggingMiddleware(RequestDelegate next, ILogger<LoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext httpContext)
{
var HttpContextBody = httpContext.Request.Body;
string requestBody = "";
httpContext.Request.EnableBuffering();
// Leave the body open so the next middleware can read it.
using (var reader = new StreamReader(
httpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: -1,
leaveOpen: true))
{
var body = await reader.ReadToEndAsync();
// Do some processing with body…
// Reset the request body stream position so the next middleware can read it
httpContext.Request.Body.Position = 0;
}
_logger.LogDebug("Middleware 1 body =" + requestBody);
await _next.Invoke(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class LoggingMiddlewareExtensions
{
public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LoggingMiddleware>();
}
}
}
有关更多信息,请参阅这些链接:
https://devblogs.microsoft.com/aspnet/re-reading-asp-net-core-request-bodies-with-enablebuffering/
.netcore 3.1 版本的@HoussamNasser 上面的回答。我创建了一个可重用函数来读取请求正文。请注意更改:HttpRequestRewindExtensions.EnableBuffering(request)
。 EnableBuffering 现在是 HttpRequestRewindExtensions class.
public async Task<JObject> GetRequestBodyAsync(HttpRequest request)
{
JObject objRequestBody = new JObject();
// IMPORTANT: Ensure the requestBody can be read multiple times.
HttpRequestRewindExtensions.EnableBuffering(request);
// IMPORTANT: Leave the body open so the next middleware can read it.
using (StreamReader reader = new StreamReader(
request.Body,
Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
leaveOpen: true))
{
string strRequestBody = await reader.ReadToEndAsync();
objRequestBody = SerializerExtensions.Deserialize<JObject>(strRequestBody);
// IMPORTANT: Reset the request body stream position so the next middleware can read it
request.Body.Position = 0;
}
return objRequestBody;
}
这个函数将return一个JObject,它可以用来读取Request Body对象的属性。 SerializerExtensions 是我用于序列化和反序列化的自定义扩展。
在中间件中,可以在构造函数中注入IHttpContextAccessor httpContextAccessor
。然后像HttpRequest request = _httpContextAccessor.HttpContext.Request;
一样访问Request对象。最后,可以像GetRequestBodyAsync(request)
我一直在努力解决它,.net core 3.1 有重大变化,“context.Request.EnableRewind();”在 .net core 3.1 中不再可用,更多有用的提示 visit here
asp.netmvc api.net core 3.1 (startup.cs)
中的工作代码 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();
}
});