Contents
- Introduction
- Types of filtering in ASP.NET MVC
- Simple understanding of Action Filter
- Using the code [Type of Action Filter, Authorization with Filter, Exception Handling]
- 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)
{
}
protected override void OnAuthorization(AuthorizationContext filterContext)
{
}
}
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)
{
}
}
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.