Как прочитать тело запроса несколько раз в промежуточном программном обеспечении asp net core 2.2?
Я попробовал это: Прочитать тело запроса дважды, и это: 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;
}
}
В контроллере я получаю "удаленный объект" или "пустой поток".
2 ответа
.netcore 3.1 версия ответа @HoussamNasser выше. Я создал многоразовую функцию для чтения тела запроса. Обратите внимание на изменение:HttpRequestRewindExtensions.EnableBuffering(request)
. EnableBuffering теперь является частью класса HttpRequestRewindExtensions.
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;
}
Эта функция вернет JObject, который может использоваться для чтения свойств объекта Request Body. SerializerExtensions - это мое собственное расширение для сериализации и десериализации.
В промежуточном программном обеспечении вы можете ввести IHttpContextAccessor httpContextAccessor
в конструкторе. А затем получите доступ к объекту запроса, напримерHttpRequest request = _httpContextAccessor.HttpContext.Request;
. Наконец, можно вызвать многоразовую функцию, напримерGetRequestBodyAsync(request)
После еще нескольких попыток и использования "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
}
});
Когда поток читается второй раз, указатель потока устанавливается в последнюю позицию. Вы должны попытаться переместить его обратно в нулевое положение, чтобы прочитать его снова с самого начала.
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/
Я боролся с этим, .net core 3.1 имеет критические изменения, "context.Request.EnableRewind();" в.net core 3.1 БОЛЬШЕ НЕТ, больше полезных советов можно найти здесь
Рабочий код в asp.net mvc 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();
}
});
Это, вероятно, из-за using
заявление вокруг вашего StreamReader
, Использование располагает StreamReader
который вызывает распоряжение на базовом потоке. Смотрите ответ здесь для более подробной информации. Вы можете попробовать сохранить ссылку и избавиться от StreamReader
после await next.Invoke();
завершается.