How to read request body multiple times in asp net core 2.2 middleware?
.netcore 3.1 version of @HoussamNasser's answer above. I have created a reusable function to read Request Body. Please note the change: HttpRequestRewindExtensions.EnableBuffering(request)
. EnableBuffering is now a part of 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;
}
This function will return a JObject which can used to read the properties of the Request Body object. SerializerExtensions is my custom extension for serializing & deserializing.
In the middleware, you can inject IHttpContextAccessor httpContextAccessor
in the constructor. And then access the Request object like HttpRequest request = _httpContextAccessor.HttpContext.Request;
. Finally, can call the reusable function like GetRequestBodyAsync(request)
After some more struggling and use "context.Request.EnableRewind()" it's finally worked like this:
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>();
}
}
}
For more info please refer to these links :
https://devblogs.microsoft.com/aspnet/re-reading-asp-net-core-request-bodies-with-enablebuffering/
https://gunnarpeipman.com/aspnet-core-request-body/