As simple as it is I am trying to replace my context.HttpContext.Response.Body with another stream.
I have come so far that I can hijack the stream but replacing it doesnt work. Now I am using the weatherforecast web-api template for this example.
public override void OnResultExecuted(ResultExecutedContext context)
{
responseBody.Seek(0, SeekOrigin.Begin);
var originalBody = context.HttpContext.Response.Body;
using var sr = new StreamReader(responseBody);
var actionResult = sr.ReadToEnd();
using var memStream = new MemoryStream();
context.HttpContext.Response.Body = memStream;
var fake = actionResult.Replace("Warm", "REPLACED", StringComparison.InvariantCultureIgnoreCase).Replace("Hot", "REPLACED", StringComparison.InvariantCultureIgnoreCase);
memStream.Position = 0;
var data = GetStreamWithGetBytes(fake, Encoding.UTF8);
memStream.Write(data, 0, data.Length);
memStream.Position = 0;
memStream.CopyToAsync(originalBody);
context.HttpContext.Response.Body = originalBody;
}
As you can se I am replacing 'Warm' or 'Hot' with REPLACED
Replacing works fine, however assigning the changed data and reading it into a stream and back in context.HttpContext.Response.Body doesn't seem to work.
Please what am I missing?
I am not looking for a middleware solution. I want to decorate our controllers with my custom action filter. So it has to be implemented with a actionfilterattribute or IActionFilter.
Here is the entire code:
public class MessageFilter : ActionFilterAttribute
{
private MemoryStream responseBody;
public override void OnActionExecuting(ActionExecutingContext context)
{
//context.HttpContext.Request.EnableBuffering();
this.responseBody = new MemoryStream();
//hijack the real stream with our own memory stream
context.HttpContext.Response.Body = responseBody;
}
public override void OnActionExecuted(ActionExecutedContext context)
{
}
public override void OnResultExecuted(ResultExecutedContext context)
{
responseBody.Seek(0, SeekOrigin.Begin);
var originalBody = context.HttpContext.Response.Body;
using var sr = new StreamReader(responseBody);
var actionResult = sr.ReadToEnd();
using var memStream = new MemoryStream();
context.HttpContext.Response.Body = memStream;
var fake = actionResult.Replace("Warm", "REPLACED", StringComparison.InvariantCultureIgnoreCase).Replace("Hot", "REPLACED", StringComparison.InvariantCultureIgnoreCase);
memStream.Position = 0;
var data = GetStreamWithGetBytes(fake, Encoding.UTF8);
memStream.Write(data, 0, data.Length);
memStream.Position = 0;
memStream.CopyToAsync(originalBody);
context.HttpContext.Response.Body = originalBody;
}
public static byte[] GetStreamWithGetBytes(string sampleString, Encoding? encoding = null)
{
encoding ??= Encoding.UTF8;
var byteArray = encoding.GetBytes(sampleString);
return byteArray;
}
}
The controller class:
using Microsoft.AspNetCore.Mvc;
using WebApplicationHttpMessageHandler.Filters;
namespace WebApplicationHttpMessageHandler.Controllers;
[ApiController]
[Route("[controller]/[action]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
[ServiceFilter(typeof(MessageFilter))]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
I am really stuck here.
change MessageFilter
as follows:
using Microsoft.AspNetCore.Mvc.Filters;
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
public class MessageFilter : ActionFilterAttribute
{
public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
if (context.Result is not ObjectResult result)
{
await base.OnResultExecutionAsync(context, next);
return;
}
var data = JsonSerializer.Serialize(result.Value);
var fake = data.Replace("Warm", "REPLACED", StringComparison.InvariantCultureIgnoreCase).Replace("Hot", "REPLACED", StringComparison.InvariantCultureIgnoreCase);
context.HttpContext.Response.ContentType = "application/json";
await context.HttpContext.Response.WriteAsync(fake);
}
}