.NET Core 3+ solution with proper resource handling:
Replace response stream by MemoryStream
to prevent its sending. Return the original stream after the response is modified:
public async Task Invoke(HttpContext context)
{
var response = context.Response;
//uncomment this line to re-read context.Request.Body stream
//context.Request.EnableBuffering();
var originBody = response.Body;
using var newBody = new MemoryStream();
response.Body = newBody;
await _next(context);
await ModifyResponseAsync(response);
newBody.Seek(0, SeekOrigin.Begin);
await newBody.CopyToAsync(originBody);
response.Body = originBody;
}
private async Task ModifyResponseAsync(HttpResponse response)
{
var stream = response.Body;
using var reader = new StreamReader(stream, leaveOpen: true);
string originalResponse = await reader.ReadToEndAsync();
string modifiedResponse = "Hello from Stackoverflow";
stream.SetLength(0);
using var writer = new StreamWriter(stream, leaveOpen: true);
await writer.WriteAsync(modifiedResponse);
await writer.FlushAsync();
response.ContentLength = stream.Length;
}
Original .NET Core 1 answer
Replace response stream by MemoryStream
to prevent its sending. Return the original stream after the response is modified:
public async Task Invoke(HttpContext context)
{
bool modifyResponse = true;
Stream originBody = null;
if (modifyResponse)
{
//uncomment this line only if you need to read context.Request.Body stream
//context.Request.EnableRewind();
originBody = ReplaceBody(context.Response);
}
await _next(context);
if (modifyResponse)
{
//as we replaced the Response.Body with a MemoryStream instance before,
//here we can read/write Response.Body
//containing the data written by middlewares down the pipeline
//finally, write modified data to originBody and set it back as Response.Body value
ReturnBody(context.Response, originBody);
}
}
private Stream ReplaceBody(HttpResponse response)
{
var originBody = response.Body;
response.Body = new MemoryStream();
return originBody;
}
private void ReturnBody(HttpResponse response, Stream originBody)
{
response.Body.Seek(0, SeekOrigin.Begin);
response.Body.CopyTo(originBody);
response.Body = originBody;
}
It’s a workaround and it can cause performance problems. I hope to see a better solution here.