The post Filters in MVC appeared first on codecompiled.
Filters
Filters is defined as an attribute which contains 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:
- 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();
}
}
- 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 their sequence in the request processing pipeline. Also, different filter types implement different interfaces. Filters and their execution sequence is as follows:
- Authentication filters: Verify if the request can execute the action method
- Authorization filters: Verify if the request is Authorized to execute the action method
- Action filters: Provide functionality which is executed before and after the action method executes
- Result filters: Provide functionality which is executed before and after the action result executes
- Exception filters: Provide functionality which executes if an unhandled error occurs
The above filters are called in a sequence. So, if both the Authentication and the Authorization filters are attached to an action method, the Authentication filter will be called before the Authorization filter.
Let's 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)
{
}
}
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 implementing 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 different filter interfaces.
As the controller
class implements these filter interfaces, 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)
{
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
}
}
So we can use the different types of filters for implementing cross cutting concerns and avoid the code duplication.
The post Filters in MVC appeared first on codecompiled.