About This Article
This article will tell you almost everything about filters used on action methods as well as on controllers in ASP.NET MVC. I am writing this article to tell you the basic to advanced foremost concepts about filters.
Last week one of my friends asked the question “How can I restrict the users to use my resources on the website?” I am dedicating this article to him. I hope he will like this.
The topics to be covered are,
- What are the Filters?
- Types of filters
- Authorization filters
- Action filters
- Result filters
- Exception filters
- Order of Filters
- Create a custom Filter in ASP.NET MVC?
- Filters provided in ASP.NET MVC
Let’s get started with Filters.
Introduction and Background
Filters are used to inject extra processing logic in the MVC request-response pipeline. You have seen in my previous article in the section of “Pipeline in MVC”, the HTTP request comes to “Routing” then goes to “Controller Initialization” then “Action Execution” and the “Result Execution” comes into action to render the view.
Now, if you want to inject some extra processing logic in between this request-response life cycle you have to use Filters or custom filters.
What are the filters?
Action filters are the attributes that can be applied on action method level, on controller level or application level. When these filters are applied on controller level then they will apply to all the actions within the controller.
Filters allow us to add pre-processing and post-processing logic to an action or controller. From this filter, the flow of the application can be changed. You can put this filter by decorating the attribute above the action method or controller. This will call the class of that attribute in which the whole logic is written.
Types of filters
There are the following types of action filters,
Filter Type | Interface | Description |
Authentication | IAuthenticationFilter | Always runs, before any action method or any other filter. |
Authorization | IAuthorizationFilter | These run first, before the action method or any other filters. |
Action | IActionFilter | These run before and after the action method. |
Result | IResultFilter | Runs before and after the action result is executed. |
Exception | IExceptionFilter | Runs only if another filter, the action method, or the action result throws an exception. |
Authorization filters
These filters are useful for implementing the logic of authentication and authorization. This will allow us to execute the action method when we want. This filter implements the IAuthorizationFilter. The examples of authorization filters are AuthorizeAttribute and RequireHttpsAttribute.
Action filters
This filter contains the pre-processing and post-processing logic which can be applied to the action method of the controller or to the entire controller. This filter is executed before and after the action method of the controller executes.
This filter implements the IActionFilter interface. And this interface contains two methods, OnActionExecuting and OnActionExecuted which will be called before and after the action method gets executed respectively. This filter allows us to add some additional processing, for example, modifying the view data that an action method of controller returns or canceling the execution of the action method of the controller.
Result filters
To use this filter, we have to implement the IResultFilter interface, and this interface contains two methods, OnResultExecuting and OnResultExecuted which will run before and after a view result is executed respectively. This filter allows us to modify the HTTP response, which means to modify the view result before the view is rendered to the browser. The OutputCacheAttribute class is an example of a result filter.
Exception Filter
The filter will execute when a controller or action method of the controller throws an unhandled exception. These filters implement the IExceptionFilter interface and can be used to log errors or to display the specific error page. The HandleErrorAttribute class is an example of the exception filter.
Note
The base class for all the action filters is the System.Web.Mvc.FilterAttribute class. Now, if you want to make your own custom type of filter, then you have to create a class that inherits the base filter class and then you have to implement one or more interfaces of the above-explained filters. See figure below, in which the interfaces of each filter is shown.
Filter Type | Interface |
Authentication Filter | IAuthenticationFilter |
Authorization Filter | IAuthorizationFilter |
Action Filter | IActionFilter |
Result Filter | IResultFilter |
Exception Filter | IExceptionFilter |
Order of filters
You have read the above five filters and their corresponding interfaces with their methods. The list is as follows,
Custom Filter in ASP.NET MVC
Now, let’s create the custom authentication filter which will redirect the user back to the login page if the user is not authenticated.
Create the project in the way shown below,
The purpose of OnAuthenticationChallenge is to restrict access of the user if the user is not authenticated. So in AuthAttribute class, you have to implement these methods. The logic to authenticate a user and to restrict user’s access is written in the following code.
- using System.Web.Mvc;
- using System.Web.Mvc.Filters;
- namespace FiltersInMvc.AuthenticationFolder
- {
- public class AuthAttribute : ActionFilterAttribute , IAuthenticationFilter
- {
- private bool _auth;
- public void OnAuthentication(AuthenticationContext filterContext)
- {
- //Logic for making a user authenticate
- _auth = (filterContext.ActionDescriptor.GetCustomAttributes(
- typeof(OverrideAuthenticationAttribute), true).Length == 0);
- }
- public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
- {
- var user = filterContext.HttpContext.User;
- if (user == null || !user.Identity.IsAuthenticated)
- {
- filterContext.Result = new HttpUnauthorizedResult();
- }
- }
- }
- }
- using FiltersInMvc.AuthenticationFolder;
- using System.Web.Mvc;
- namespace FiltersInMvc.Controllers
- {
- public class HomeController : Controller
- {
- [Auth]
- public ActionResult Index()
- {
- return View();
- }
- public ActionResult About()
- {
- ViewBag.Message = "Your application description page.";
- return View();
- }
- public ActionResult Contact()
- {
- ViewBag.Message = "Your contact page.";
- return View();
- }
- }
- }
Now, I am going to apply authorization filter in this sampled application. These filters are used to enforce authorization policy in which the action method can only be invoked by approved or authenticated users. As you know, these filters are run before the action method is invoked and these implement the IAuthorizationFilter interface. The look and feel of IAuthorizationFilter interface is as follows;
- namespace System.Web.Mvc
- {
- /// <summary>Defines the methods that are required for an authorization filter.</summary>
- public interface IAuthorizationFilter
- {
- /// <summary>Called when authorization is required.</summary>
- /// <param name="filterContext">The filter context.</param>
- void OnAuthorization(AuthorizationContext filterContext);
- }
- }
- /// <summary>When overridden, provides an entry point for custom authorization checks.</summary>
- /// <returns>true if the user is authorized; otherwise, false.</returns>
- /// <param name="httpContext">The HTTP context, which encapsulates all HTTP-specific information about an individual HTTP request.</param>
- /// <exception cref="T:System.ArgumentNullException">The <paramref name="httpContext" /> parameter is null.</exception>
- protected virtual bool AuthorizeCore(HttpContextBase httpContext);
- using System.Web;
- using System.Web.Mvc;
- namespace FiltersInMvc.AuthenticationFolder
- {
- public class AuthZAttribute : AuthorizeAttribute
- {
- private readonly bool _localReq;
- public AuthZAttribute(bool reqReq)
- {
- _localReq = reqReq;
- }
- protected override bool AuthorizeCore(HttpContextBase httpContext) nbsp;
- {
- if (httpContext.Request.IsLocal)
- {
- return _localReq;
- }
- else
- {
- return true;
- }
- }
- }
- }
- using System.Web.Mvc;
- namespace FiltersInMvc.Controllers
- {
- public class HomeController : Controller
- {
- [Authorize]
- public ActionResult Index()
- {
- return View();
- }
- public ActionResult About()
- {
- ViewBag.Message = "This is the article by Zain.";
- return View();
- }
- public ActionResult Contact()
- {
- ViewBag.Message = "Your contact page.";
- return View();
- }
- }
- }
Now, put Authorize attribute to About action method, as shown below,
I am decorating Contact action method with Authorize attribute and specifying the user’s email as “zainshah@outlook.com” so my previous email would not work at all. Let’s see the code.
- using System.Web.Mvc;
- namespace FiltersInMvc.Controllers
- {
- public class HomeController : Controller
- {
- //[Authorize]
- public ActionResult Index()
- {
- return View();
- }
- [Authorize(Users="syedzain@outlook.com")]
- public ActionResult About()
- {
- ViewBag.Message = "This is the article by Zain.";
- return View();
- }
- [Authorize(Users="zainshah@outlook.com")]
- public ActionResult Contact()
- {
- ViewBag.Message = "Your contact page.";
- return View();
- }
- }
- }
Filters provided in ASP.NET MVC
ASP.NET MVC provide us with some filters that can be implemented as attributes. And these are applicable at the level of action method, the controller or the whole application.
- AuthorizeAttribute
- HandleErrorAttribute
- OutputCacheAttribute
- RequireHttpsAttribute
This filter is used to restrict access by authentication and authorization. In other words, this is an attribute that can be used to restrict access to the action methods of the controller by callers.
Syntax
- namespace System.Web.Mvc
- {
- /// <summary>Specifies that access to a controller or action method is restricted to users who meet the authorization requirement.</summary>
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
- public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
- {
- //Some code here.
- }
- }
When an unauthorized user tries to access the action method of the controller which is decorated with AuthorizeAttribute, then the user gets 401 HTTP status code. But if ASP.NET forms authentication is set in the website then 401 status code causes the browser to redirect the user to the login page.
Example
We have already seen the example of AuthorizeAttribute used in authorization section above. Here you will just see the sampled example and its result (without proper images of outputs).
Below you can see the example in which there is a controller (HomeController) who has total 5 action methods in which three methods are decorated with Authorize attribute and two methods are not decorated with an attribute.
- public class HomeController: Controller
- {
- public ActionResult Index()
- {
- ViewData["Message"] = "This is Zain’s article!";
- return View();
- }
- public ActionResult About()
- {
- return View();
- }
- [Authorize]
- public ActionResult AuthenticatedUsers()
- {
- return View();
- }
- [Authorize(Roles = "Admin, Super User")]
- public ActionResult AdministratorsOnly()
- {
- return View();
- }
- [Authorize(Users = "Zain@outlook.com, syed@outlook.com")]
- public ActionResult SpecificUserOnly()
- {
- return View();
- }
- }
HandleErrorAttribute
This filter is used to handle an exception thrown by an action method. Let’s move to see its syntax.
Syntax
- namespace System.Web.Mvc
- {
- /// <summary>Represents an attribute that is used to handle an exception that is thrown by an action method.</summary>
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
- public class HandleErrorAttribute : FilterAttribute, IExceptionFilter
- {
- //Some code here
- }
- }
- ExceptionType
Specifies the type of exception that is handled by the filter. The return type of this property is Type, which means it returns the type of exception that occurred. We can modify its default behavior. - Master
This property gets or sets the master view for displaying exception information. The return type of this property is a string so that it can display exception information. - TypeId
This property is used to get the unique identifier for the HandleErrorAttribute. We can’t modify or set the value for this property. - ViewThis property is used to get or set the page view for displaying exception information. We can set the view page name for this attribute. As we know when the action method throws an exception, MVC displays an Error view in a Shared folder located in View folder. MVC framework sends information of exception in the ViewDictionary object. And the Model property of this view is set to an instance of the ExceptionContext class. The ViewData dictionary contains the values for the keys:
- ActionName - The intended action method who throws an exception.
- ControllerName - The intended controller in which the action method throws an exception.
- Exception - The exception object was thrown by the action method of the controller.
To use HandleErrorAttribute, let’s some change in the project FiltersInMvc. Follow the steps given below:
Step 1
Add an action method with the name of CustomException in the HomeController
- public ActionResult CustomException()
- {
- throw new Exception("Something went wrong!");
- }
Go to Shared folder, then open _Layout.cshtml and add the following line of code for the navigation bar.
- <li>@Html.ActionLink("Custom Exception", "CustomException", "Home")</li>
Code of HomeController is as follows,
- using System;
- using System.Web.Mvc;
- namespace FiltersInMvc.Controllers
- {
- public class HomeController : Controller
- {
- public ActionResult Index()
- {
- return View();
- }
- [Authorize(Users="syedzain@outlook.com")]
- public ActionResult About()
- {
- ViewBag.Message = "This is the article by Zain.";
- return View();
- }
- [Authorize(Users="zainshah@outlook.com")]
- public ActionResult Contact()
- {
- ViewBag.Message = "Your contact page.";
- return View();
- }
- public ActionResult CustomException()
- {
- throw new Exception("Something went wrong!");
- }
- }
- }
- <li>@Html.ActionLink("Custom Exception", "CustomException", "Home")</li>
But the problem with the output here is, it has the code of the application, which can be helpful for a hacker. So we can display any friendly error page. This can be done in two ways,
- Go to Web.config file of the root directory, then go to system.web section and place the following element in that section,
- <customErrors mode="On"></customErrors>
- Place user-friendly text in the Error.cshtml file in Shared You can see below the screenshot of code,
- Now simply build and run the application, go to /Home/CustomException URL then you should see the output given below,
Answer
Look, this is all due to HandleError attribute which is already added to the GlobalFilters collection in global.asax file. When a filter is added to the GlobalFilters collection, then it is applicable to all the controllers and their action methods in the entire application. You can see the code below,
Now if we comment on this line of code, then what happened?
- [HandleError]
- public ActionResult CustomException()
- {
- throw new Exception("Something went wrong!");
- }
OutputCacheAttribute
This filter is used to decorate an action method of a controller whose output will be cached.
Syntax
- [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
- public class OutputCacheAttribute : ActionFilterAttribute, IExceptionFilter
- {
- //Some code here
- }
To use OutputCacheAttribute, let’s some change in the project FiltersInMvc. Follow the steps given below:
Step 1
Add an action method with the name of Test in the HomeController
- [OutputCache(Duration = 10)]
- public ActionResult Test()
- {
- ViewData["Message"] = "This page was cached at " + DateTime.Now;
- return View();
- }
Go to Shared folder, then open _Layout.cshtml and add the following line of code for the navigation bar.
- <li>@Html.ActionLink("Test OutputCacheAttribute", "Test", "Home")</li>
Add the View with the name of Test. Code of Test view is as follows,
- @{
- ViewBag.Title = "Output";
- }
- <h2>Output</h2>
- <p>
- @Html.Encode(ViewData["Message"])
- </p>
Simply build and run the application. You should see the below output.
When you repeatedly click within 10 seconds, then you will not see any change in the time. But after 10 seconds you can see the change in time. Hence in his fashion, you can store the output of an action method for the specified time.
RequireHttpsAttribute
RequireHttpsAttribute is used to force an un-secured HTTP request to be re-sent over HTTPS.
To use RequireHttpsAttribute, let’s some change in the project FiltersInMvc. Follow the steps given below:
Step 1
Add an action method with the name of Force in the HomeController
- public string Force()
- {
- return @"This method 'Force' should be accessed only using HTTPS protocol.";
- }
- [RequireHttps]
- public string Force()
- {
- return @"This method 'Force' should be accessed only using HTTPS protocol.";
- }
Conclusion
I hope this article has helped you in understanding all the concepts about filters. If you have any query then feel free to contact me in the comments section. Also, give feedback, either positive or negative, it will help me to make my articles better and increase my enthusiasm to share my knowledge.
No comments:
Post a Comment