Best way to abort/cancel action and response from ActionFilter
Asked Answered
C

6

40

Best way to abort/cancel action from ActionFilter

I've got this ActionFilter, and it's suppose to end the connection immediately and return a 401 Unauthroized:

public class SignInRequired : ActionFilterAttribute 
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // User is verified, continue executing action

        if (Acme.Web.CurrentUser != null)
        {
            return;
        }

        // End response with 401 Unauthorized

        var response = HttpContext.Current.Response;
        response.StatusCode = (int)HttpStatusCode.Unauthorized;
        response.End();

        // Prevent the action from actually being executed

        filterContext.Result = new EmptyResult();
    }
}

I learned how you can cancel the action from executing by setting 'context.Result = new EmptyResult()` here, but I'm not sure if this is the best way to flush the response and close the connection.

Cassandry answered 3/3, 2011 at 20:55 Comment(1)
also wondering how to return 401. Although your solution works for me, none of answer helped me.Thurible
A
31

Setting the response will mean the action doesn't get called.

public override void OnActionExecuting(HttpActionContext actionContext)    
{ 
    actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
}

As other answers have said, though, authentication should be done with an AuthorizeAttribute (Docs for Web.API or for MVC).

Anneal answered 4/8, 2015 at 11:38 Comment(1)
This will probably cause a redirect to the presumed login page. That might not be the desired behaviour.Harper
C
23

On .net core 2.2, 3.0 and 3.1 and .net 5 the below example works fine

public override void OnActionExecuting(ActionExecutingContext context)
{
  context.Result = new UnauthorizedObjectResult("user is unauthorized");
}
Corrinecorrinne answered 6/8, 2020 at 17:39 Comment(1)
This is valid on .NET core 3.1Carolacarolan
O
8

The answer that @OdeyinkaOlubunmi is correct for Web API or specifically System.Web.Http.Filters.ActionFilterAttribute but it can't be used for System.Web.Mvc.ActionFilterAttribute. AuthorizeAttribute and overriding AuthorizeCore is a good way to go but if you use @Vadim's example for a GlobalFilter you will end up with the following error in a standard configuration:

HTTP Error 404.15 - Not Found The request filtering module is configured to deny a request where the query string is too long.

This is because the default /Login?ReturnUrl= will keep appending new values until the query string causes an exception.

The way I have solved it for MVC is like this:

public class DebugActionFilter : System.Web.Mvc.ActionFilterAttribute
{
  public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext actionContext)
  {
    actionContext.Result = new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
    return;
  }
}
Odessa answered 25/1, 2018 at 13:52 Comment(0)
F
3

You can set the result of filterContext for the Exception page like this:

filterContext.Result = new RedirectResult("~/Error/Unauthorized");

See more details here on section Canceling Filter Execution

Fascinate answered 27/9, 2013 at 13:48 Comment(0)
E
2

You probably want to make it an AuthorizeAttribute. That will set the result to be an UnAuthorizedResult automatically, plus it has the benefit of being run before any other filters. Alternatively you can set the Result to be a new HttpUnauthorizedResult

public class SignInRequiredAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        return !Acme.Web.CurrentUser != null;
    }
}
Erickson answered 3/3, 2011 at 21:6 Comment(0)
P
2

using .net core 2.1 the solutions above did not work for me , so i tried this and it worked :-

 context.HttpContext.Response.StatusCode = 401;
 return;

if there is better solutions for .net core 2.1 i am open for suggestions

Precipitant answered 17/1, 2019 at 8:20 Comment(1)
Just use return RedirectToAction("Someactionname"); Btw in 2.1 it is this.ControllerContext.HttpContext.Response.StatusCode = 401;Confectioner

© 2022 - 2024 — McMap. All rights reserved.