When I use context.HttpContext.Response.Body.Write or context.HttpContext.Response.WriteAsync inside an ActionFilterAttribute I get errors in the pipeline that the response has already started.
System.InvalidOperationException: StatusCode cannot be set because the response has already started.
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ThrowResponseAlreadyStartedException(String value)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.set_StatusCode(Int32 value)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncCore(ActionContext context, ObjectResult result, Type objectType, Object value)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsync(ActionContext context, ObjectResult result)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextResultFilterAsync[TFilter,TFilterAsync]()
Exception is better described in this issue Unable to write to response using Action filter - OnActionExecuted method
One comment says that a solution is to end the request in the filter, which would work in my case, but I have no idea how to do it.
I tried using Flush, CompleteAsync, assigning value to context.Result, which says will short-circuit the remaining filter, but it didn't work.
What is the right way to end the request/response inside a filter?
Edit: Example of a filter that throws the error:
[HttpGet, MyFilter]
public ContentResult MyAction()
{
return new ContentResult() {Content = "test"};
}
public class MyFilter : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext context)
{
// Get the response object from the context
var response = context.HttpContext.Response;
// Write some data to the response
response.ContentType = "text/plain";
response.WriteAsync("This is some data from the filter!").Wait();
}
}
Answering my own question.
Set the context.Result = null; (short-circuit the filters) in OnActionExecuted, and then write the desired data in OnResultExecutionAsync using Write, WriteAsync, CopyToAsync or whatever else.
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