views:

129

answers:

2

By default, the MVC Authorize attribute sets the HttpContext.Response.StatusCode = 401 when a user is not authorized and the section in the web.config routes to the loginUrl property.

I want to do something similar with other response codes. For example, I have an attribute called ActiveAccount which verifies the user's account is currently active and then allows them access to the controller. If they are not active I want to route them to a specific controller and view (to update their account).

I'd like to copy the Authorize attributes way of handling this and set the StatusCode to something like 410 (warning: preceding number pulled out of thin air) and have the user routed to a location defined in the web.config file.

What can I do to implement this behavior? Or is there a simpler method?

Edit: Results

I ended up avoiding the StatusCode and just performing a redirection from within the attribute as this was much simpler. Here is my code in a nutshell:

// using the IAuthorizationFilter allows us to use the base controller's 
//   built attribute handling.  We could have used result as well, but Auth seems
//   more appropriate.
public class ActiveAccountAttribute: FilterAttribute, IAuthorizationFilter
{

    #region IAuthorizationFilter Members

    public void OnAuthorization(AuthorizationContext filterContext)
    {

        if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            return;

        // ... code which determines if our customer account is Active

        if (!user.Status.IsActive)
            filterContext.Result = new RedirectToRouteResult("Default", new RouteValueDictionary(new {controller = "Account"}));
    }

    #endregion
}
+2  A: 

You could inherit the RedirectToRouteResult class and add a constructor parameter for the status code.

public class StatusRedirectResult : RedirectToRouteResult

    private string _status;

    public StatusRedirectResult(string action, RouteValueDictionary routeValues, string statusCode)
    {
        _status = statusCode;
        base.RedirectToRouteResult(action, routeValues);
    }

    public override ExecuteResult(ControllerContext context)
    {
        context.HttpContext.Current.Response.Status = _status;
        base.ExecuteResult(context);
    }
}

To use this in a controller action, just

return StatusRedirect("NewAction", new RouteValueDictionary(new { controller = "TheController" }, "410");
Tomas Lycken
I was in the middle of trying to implement something similar when I saw this answer, although your example was better. The "410" part becomes completely unnecessary when resorting to the RedirectToRoute, thus eliminating the StatusRedirectResult class. The attribute itself can just perform the redirection. I post my code shortly at the bottom of my question.
Sailing Judo
A: 

it should be two piece of code.

in your controller you return an error code by

Response.StatusCode = (int)HttpStatusCode.NotFound;

then you custom error code to desired route

<customErrors mode="On">
     <error statusCode="404" redirect="~/Profile/Update" />
</customErrors>
Jirapong
I tried this idea and it just didn't work out. I didn't really try to debug it to find out what was wrong (basically the browser just displayed nothing).
Sailing Judo