Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get HttpStatus code from IActionFilter in .Net Core 2.0

I have filter attribute in ASP.NET core 2.0, See my code snippet below. Here the problem is I always get the status code is 200.

Even the actual status code is 500 then also I get a 200. How do I get the actual status code?

public void OnActionExecuted(ActionExecutedContext context)
{
    try
    {
        var controller = context.Controller as APIServiceBase;
        var statusCode = controller.Response.StatusCode;
        ..
        ..
    }
    catch { }

}
like image 416
blue Avatar asked Mar 19 '18 20:03

blue


2 Answers

Quite an interesting question. Action filters are executed just after the action itself. The problem is that IActionResult returned by the action is not yet executed at this stage. You could check it by returning your custom implementation of IActionResult and checking that its ExecuteResultAsync method is executed after OnActionExecuted() of the action filter .

Since response is populated by IActionResult (including status code), you shouldn't expect that Response.StatusCode will be already set in action filter.

To solve this problem you should execute your logic later in ASP.Net Core pipeline, action filter is just not a proper place for it. You could add custom middleware in request pipeline (Startup.Configure() method):

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.Use(async (context, next) =>
    {
        await next.Invoke();
        var statusCode = context.Response.StatusCode;
        // ...
    });

    app.UseMvc();
}

Make sure you add it before call to app.UseMvc(). You could wrap delegate logic to separate class if required.

like image 135
CodeFuller Avatar answered Oct 30 '22 18:10

CodeFuller


As raised by CodeFuller, your action may not have been executed yet. However if you want to keep a filter-pattern to apply it only to specific methods, you may get use of the OnCompleted method of the response:

// Called on incoming request
public void OnActionExecuting(ActionExecutedContext context)
{
    context.HttpContext.Response.OnCompleted(async () => {
        // Executed once the response is sent

        var status = context.HttpContext.Response.StatusCode;

        // Work here
        // Be careful on Transient or Scoped injections, they may already be disposed
        // If you need a DbContext, instanciate it by injecting 
        //    DbContextOptions<MyDbContext> earlier in the code

    });
}

This method should work for most types of filter, so you may use a any depending on the filter inputs you need.

like image 29
Jean Avatar answered Oct 30 '22 20:10

Jean