Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Simple Action Filter Overview for Authorization and Exception Handling in ASP.NET MVC

0.00/5 (No votes)
10 Dec 2013 1  
A simple action filter overview for authorization and exception handling in ASP.NET MVC.

Contents

  1. Introduction
  2. Types of filtering in ASP.NET MVC
  3. Simple understanding of Action Filter
  4. Using the code [Type of Action Filter, Authorization with Filter, Exception Handling]
  5. Conclusion

Introduction

Earlier, we used traditional try..catch block or globally catch exception in ASP.NET. Also ASP.NET has several traditional ways to handle authorization like session storage of user information and others. But in ASP.NET MVC has a much more smarter way to handle authorization and exception handling capability using filtering while requesting to Action through controller. I am going to describe a practical implementation for ASP.NET MVC application to implement authorization and exception. Eventually, I also discussed with the fundamental of filtering of ASP.NET MVC.

Types of Filters in ASP.NET MVC

ASP.NET has a great feature: request filter to action. All filters work when an action invoker starts to the end of the execution process, that means before sending processed data to the client. There are four types of action filters:

  • Authorization filter: to authorize a request, we can add the filter object in Global.asax. The interface that needs to be implemented for this filter is IAuthorizationFilter.
  • Action filter: IActionFilter will be implemented if we want to use this filter.
  • Result filter: This is a very important filtering for data, incoming and outgoing, because it has two events that are fired before and after the action is invoked. We will have to implement IResultFilter.
  • ExceptionFilter: Implementing the IExceptionFilter attribute, we can catch any exception and process further.

Using the Code

For example, you are developing an ASP.NET MVC application but no security and exception handling mechanism had been implemented yet. So you will have to implement those and the best approach is to filter action against a single controller or globally for all controllers or registering a filter attribute so that all actions have been passed by the filtering process. As we know, ASP.NET MVC's entry point is an action through controller so if we can take any of the above approaches, then the overall application's behavior will be secured, or a global exception handler.

For the controller, all controllers already have four types of the above filter, because it implements IActionFilter, IResultFilter, IAuthorizationFilter, and IExceptionFilter. So, we can override OnAuthorization/ OnExecuting for authorization and OnException for exception handling. But we have to write individually for all controllers of the application.

On the other hand, we can create a BaseController by inheriting the Controller class and override those above events for authorization and exception. Then every controller must inherit BaseController rather than standard MVC controller so that every action comes through the filtering process.

public class BaseController : Controller
{
    protected void SetAuthInfo(Guid Id, string Email, string FullName, string Role)
    {
        AuthUtil.SetAuthInfo(Id, Email, FullName, Role);
    }
    protected override void OnException(ExceptionContext filterContext)
    {
        //write your custom code here
    }
    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        //write your custom code here
    }
}
public class Home:BaseController
{
    public ActionResult Index()
    {
        return View();
    }  
}    

Another approach is to write a class and register it to global.asax. Add a class for authorization and register globally:

public class LogOnAuthoRization: AuthorizeAttribute
{     
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        var isAuthorised = base.IsAuthorized(actionContext);

        if (isAuthorised)
        {
            var cookie = HttpContext.Current.Request.Cookies
            [FormsAuthentication.FormsCookieName];
            var ticket = FormsAuthentication.Decrypt(cookie.Value);
            var identity = new GenericIdentity(ticket.Name);
            string userData = ticket.UserData;
            if (userData.Contains("_"))
            {
                string[] data = userData.Split('_');
                if (data != null && data.Length > 3)
                {
                    string Email = data[0];
                    string Id = data[1];
                    string FullName = data[2];
                    string Role = data[3];
                    var principal = new CustomUserPrincipal
                    (identity, new Guid(Id), Email, Role, FullName);
                    HttpContext.Current.User = principal;
                    Thread.CurrentPrincipal = principal;
                }
            }
        }
    }
} 

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CPExceptionHandler());
        filters.Add(new LogonAuthorizeAttribute());            
    }

    internal static void RegisterHttpFilters(System.Web.Http.Filters.HttpFilterCollection filters)
    {
        filters.Add(new APIAuthorizeAttribute());       
    }
} 

Registering global.asax in the Application_Start method.

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

For exception handling, you have to follow the above approach. But for exception, you need to write a class by inheriting HandleErrorAttribute (if you want to register globally not BaseController or individual controller approach). Later, you have to register by calling the FilterConfig.RegisterGlobalFilters in Application_Start method. The class for Exception handling will look like:

public class CPExceptionHandler : HandleErrorAttribute
{
    public override void OnException(ExceptionContext filterContext)
    {
        //redirect to error page and do your necessary task here
    }
} 

You have seen in a earlier code block I register "CPExceptionHandler" this class for global filter.

Sometimes we need to execute a specific task depends on action's behavior. For example, if a owner of a web site wants to know immediately when a user visits a specific view. Then the owner expects to get a mail from the application automatically. For this type of scenario, we can use Action Filter. After execution an action, the application will generate a mail and sent to the owner automatically.

public class MyActivityFilter : ActionFilterAttribute{
  public override void OnActionExecuting(ActionExecutingContext filterContext)
  {
  }
   public override void OnActionExecuted(ActionExecutedContext filterContext)
   {
    Task.Factory.StartNew(() => Email(filterContext));
   }
  public override void OnResultExecuting(ResultExecutingContext filterContext)
   {
   }
  public override void OnResultExecuted(ResultExecutedContext filterContext)
  {
  }
}

In the above code, the MyActivityFilter class inherits ActionFilterAttribute. The ActionFilterAttribute class implements the IActionFilter interface.

Conclusion

By using the above, a different approach need not be followed at a time. I suggest writing your own filtering class and registering it globally. One thing I did not mention here is "How to do exception and authorization handling for WebAPI and AJAX". The next part of this article will be on this topic. But if your requirement is like the above scenario, then you can follow it anyway. There is nothing like a smart way to handle authorization and exception handling.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here