I need to append some info to each JSON answer of every action of controller. For this, I make base controller inherited from standard MVC Controller
class.
I try like this. But I catch ArgumentException
with message like this "Stream was not readable." Probably stream was closed when ActionResult
object wrote data to body. What can I do?
public override void OnActionExecuted(ActionExecutedContext context)
{
var respApi = new ResponseApiDTO();
respApi.Comment = "You could!!!";
JObject jRespApi = JObject.FromObject(respApi);
Stream bodyStream = context.HttpContext.Response.Body;
JObject jbody;
context.Result = Json(jbody);
using( var rd = new StreamReader(bodyStream))
{
string bodyText = rd.ReadToEnd();
jbody = (JObject)JsonConvert.DeserializeObject(bodyText);
jbody.Add(jRespApi);
context.Result = Json(jbody);
}
}
I`ve find a solve. We need to replace the Body stream to MemoryStream object while executing MVC step in pipeline. And then we must return original stream object object into Response.Body.
// Extension method used to add the middleware to the HTTP request pipeline.
public static class BufferedResponseBodyExtensions
{
public static IApplicationBuilder UseBufferedResponseBody(this IApplicationBuilder builder)
{
return builder.Use(async (context, next) =>
{
using (var bufferStream = new MemoryStream())
{
var orgBodyStream = context.Response.Body;
context.Response.Body = bufferStream;
await next();//there is running MVC
bufferStream.Seek(0, SeekOrigin.Begin);
await bufferStream.CopyToAsync(orgBodyStream);
context.Response.Body = orgBodyStream;
}
});
}
}
Then include this into the pipline. Class Startup, method Configure.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseBufferedResponseBody();
app.UseMvc();
...
}
And after replacing responses body stream you can read and modify body contents via Result Filter.
public class ResultFilterAttribute : Attribute, IResultFilter
{
public async void OnResultExecuted(ResultExecutedContext context)
{
Stream bodyStream = context.HttpContext.Response.Body;
bodyStream.Seek(0, SeekOrigin.Begin);
string bodyText = rd.ReadToEnd();
}
}
This attribute must be aplied to the target Controller class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With