Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write to response using Action filter

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();
    }
}
like image 496
Desperado Avatar asked Feb 02 '26 06:02

Desperado


1 Answers

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.

like image 88
Desperado Avatar answered Feb 03 '26 18:02

Desperado