Filters
Filter is implemented as an attribute which defines the common functionality or the cross cutting concern.The logic contained in a filter executes when the action method with which the filter is attached executes.Common examples of such cross cutting concerns are the logging and the caching functionality .Logging is used across the different layers in an application so it makes sense to encapsulate such functionality.
Instead of duplicating such functionality across different action methods and controllers ,we can encapsulate the common functionality in a filter.So we define a filter once and then apply it to the different controllers and action methods.
We can apply a filter to an action method or to a controller,applying a filter to a controller has the same effect as applying the filter to each of the action methods in a controller.
So the following two code snippets are effectively the same :-
1)Attaching filter to a controller
In the following example we are attaching the HandleError filter to the Home Controller.
[HandleError] public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult About() { return View(); } }
2)Attaching filter to action methods in a controller
In the following example we are attaching the HandleError filter to each of the action methods in the Home Controller..
public class HomeController : Controller { [HandleError] public ActionResult Index() { return View(); } [HandleError] public ActionResult About() { return View(); } }
Different types of filters
Filters are classified in the following types according to the types of functionality which they provide and there sequence in the request processing pipeline. Also different filter types implements different interfaces.Filters and their execution sequence is as follows
- Authentication filters Verifies if the request can execute the action method
- Authorization filters Verifies if the request is Authorized to execute the action method
- Action filters Provides functionality which is executed before and after the action method executes
- Result filters Provides functionality which is executed before and after the action result executes
- Exception filters Provides functionality which executes if an unhandled error occurs
The above filters are called in a sequence.So ,if we both the Authentication and the Authorization filters are attached to an action method ,the Authentication filter will be called before the Authorization filter
Lets see how we can use the above filters
Authentication filter is the first filter to execute and is used to authenticate the request.Authentication filter was introduced in MVC 5.
Authentication filter implements the filter IAuthenticationFilter interface which is defined as
public interface IAuthenticationFilter { void OnAuthentication(AuthenticationContext filterContext); void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext); }
OnAuthetication method is the first of all the filter methods which gets called.We can allow or deny access to the user making the request in this method.So this is the method in which we can implement our authentication policy.It is passed a parameter of the type AuthenticationContext. AuthenticationContext has a property Result of type ActionResult.
If we want to deny the access to action method for the current request then we can assign a HttpUnauthorizedResult object to the Result property as:-
public class AuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter { public void OnAuthentication(AuthenticationContext filterContext) { filterContext.Result = new HttpUnauthorizedResult(); } public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext) { // filterContext.Result = new ViewResult(); } }
If we apply the AuthenticationAttribute to any action method the following login screen is displayed.As we have set the result property to HttpUnauthorizedResult type so the user is redirected to the login screen.
Authorization filter implements the IAuthorizationFilter interface which is defined as
public interface IAuthorizationFilter { void OnAuthorization(AuthorizationContext filterContext); }
Instead of creating a custom Authorization filter attribute ,there is a built in AuthorizeAttribute which we can use to define the authorization policy. This attribute has two important properties
- Users A comma separated list of users who are allowed to access the action method.
- Roles A comma separated list of roles which are allowed to access the action method.
The following Authorize attribute limits the access to the action method only to the user “user1”.
[Authorize(Users="user1")] public ActionResult Index() { return View(); }
Action filter We use action filters to define the functionality which we want to execute before an action method executes or after an action method executes.
Normally we define custom functionality using the Action filters.Though there are few built in Action filters also.OutputCache is an example of a built in action filter
Action filters implements the IActionFilter interface.This interface is defined as
public interface IActionFilter { void OnActionExecuting(ActionExecutingContext filterContext); void OnActionExecuted(ActionExecutedContext filterContext); }
- OnActionExecuting defines the functionality which we want to execute before the action method executes
- OnActionExecuted defines the functionality which we want to execute after the action method executes
So we can define an action filter by defining a class implemeting IActionFilter interface as:-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] public class ActionTestAttribute : FilterAttribute, IActionFilter { public void OnActionExecuted(ActionExecutedContext filterContext) { filterContext.HttpContext.Response.Write("Action method executed."); } public void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.HttpContext.Response.Write("Action method going to execute </br>"); } }
So we get the following response in browser if we apply the above filter attribute to any action method.
As we have implemented the OnActionExecuting and OnActionExecuted methods so our filter logic executes before the action method executes and after the action method executes.
Result filter Defines functionality which executes after the action result is returned by the action method.Result filters implement the interface IResultFilter which is defined as
public interface IResultFilter { void OnResultExecuting(ResultExecutingContext filterContext); void OnResultExecuted(ResultExecutedContext filterContext); }
- OnResultExecuting executes after the action result is returned by the action method but before the action result executes
- OnResultExecuted executes after the action result completes execution.
Exception filter We use exception filters to handle exceptions which are not handled in our action method.Exception filters implements the interface IExceptionFilter which is defined as:-
public interface IExceptionFilter { void OnException(ExceptionContext filterContext); }
The OnException method is called when an unhandled exception occurs.
Instead of creating a class implementing the IExceptionFilter interface we can use the built in HandleError attribute. HandleError attribute defines the following two important properties
- ExceptionType The type of exception the HandleError attribute will handle
- View The view that is rendered if an unhandled error occurs.
To handle the ArgumentNullException we can apply the HandleError attribute as
[HandleError(ExceptionType=typeof(ArgumentNullException),View="CustomError")] public ActionResult Details(int id) { return View(); }
If no value is passed for the action method’s id parameter then the view specified in the View property will be displayed to the user.
Overriding the Controller base class methods
As we have seen above we can create custom filters by creating an attribute and then attaching the attribute to the controller or the action method.Instead of explicitly defining the attributes implementing these interfaces we can directly implement the methods defined by these interfaces in the controller class.The controller class implements all the the different filter interfaces.
As the controller class implements these filter interface so it defines the methods declared by these interfaces.These methods are defined as virtual which we can override in our controller class :-
protected virtual void OnActionExecuted(ActionExecutedContext filterContext); protected virtual void OnActionExecuting(ActionExecutingContext filterContext); protected virtual void OnAuthentication(AuthenticationContext filterContext); protected virtual void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext); protected virtual void OnAuthorization(AuthorizationContext filterContext); protected virtual void OnException(ExceptionContext filterContext); protected virtual void OnResultExecuted(ResultExecutedContext filterContext); protected virtual void OnResultExecuting(ResultExecutingContext filterContext);
So instead of applying the action filter attributes to our action methods or the controller we can override the above methods in our controller class as:-
public class HomeController : Controller { protected override void OnActionExecuting(ActionExecutingContext filterContext) { // executes before the action method execution } protected override void OnActionExecuted(ActionExecutedContext filterContext) { // executes after the action method executes } }
So we can use the different types of filters for implementing cross cutting concerns and avoid the code duplication.
Leave a Reply