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
The question is how to restrict the user to stop the usage of website resources. So this can be done using Filters 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”, that 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 the 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. |
Now let’s understand each filter with examples. (Examples are given in the “Filters provided in ASP.NET MVC” section)
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. 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. 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 the 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 modifying 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 the figure below, in which the interfaces of each filter are shown.
Filter Type |
Interface |
Authentication Filter |
IAuthenticationFilter |
Authorization Filter |
IAuthorizationFilter |
Action Filter |
IActionFilter |
Result Filter |
IResultFilter |
Exception Filter |
IExceptionFilter |
We’ll see how to create the custom filter later in this article. First, look at the order of these filters in which they will execute.
Order of filters
You have read the above five filters and their corresponding interfaces with their methods. The list is as follows.
Now, suppose that we are using all the above filters on one action method, then what will be the order of its execution? So the order will be as follows.
As we know if the exception occurred in the application then the application returns an exception instead of returning the result view. So for the Exception filter, if the exception has occurred then the IExceptionFilter.OnException will be called instead of Result Filters (IResultFilter.OnResultExecuting and IResultFilter.OnResultExecuted).
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,
Select MVC then click OK.
Build and run your application simply and you will prompt the following page on the browser which will call from the Index action method of the HomeController. You can see this page is not prompted to the login page. But when we make an authentication filter and apply it on HomeController then we’ll redirect to the login page.
Now, make a folder with the name of AuthenticationFolder in the project.
Then make a class with the name of AuthAttribute and inherit it from IAuthenticationFilter and IActionFilter. You can see below the look and feel of the IAuthenticationFilter interface in which two methods OnAuthentication and OnAuthenticationChallenge are declared. The purpose of OnAuthentication is to be executed first and to perform the needed authentication logic.
The purpose of OnAuthenticationChallenge is to restrict access of the user if the user is not authenticated. So in the 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();
}
}
}
}
Now, we’ll apply this filter on the HomeController. So go to HomeController.cs class and decorate the controller with the Auth attribute as shown in the figure below.
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, simply build and run the application and you will be prompted to the login page instead of the home page, as shown in the figure below.
Now I’ll register myself with my supposed credentials.
And then I’ll log in with the same credentials.
When you click on your Name then you will be redirected to Manage Controller in which you can manage your account settings such as change password etc. See the figure below.
Authorization Filter
Now, I am going to apply an authorization filter in this sampled application. These filters are used to enforce an 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 the 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);
}
}
Now, let’s make a class with the name of AuthZAttribute to apply the authorization policy. For authorization, you have to inherit the AuthAttribute class to AuthorizeAttribute. In this example, I’ll use the built-in feature of the Authorize attribute. For this, you have to override the AuthorizeCore (HttpContextBase httpContext) method from the AuthorizeAttribute class. The look and feel of the AuthorizeCore method are as follows.
/// <summary>
/// When overridden, provides an entry point for custom authorization checks.
/// </summary>
/// <param name="httpContext">The HTTP context, which encapsulates all HTTP-specific information about an individual HTTP request.</param>
/// <returns>True if the user is authorized; otherwise, false.</returns>
/// <exception cref="System.ArgumentNullException">The <paramref name="httpContext" /> parameter is null.</exception>
protected virtual bool AuthorizeCore(HttpContextBase httpContext);
As you can see in the comments, the purpose to this method is to return true if the user is authorized; otherwise false. So it will provide us authorization logic and we’ll override it shortly. Let’s write some code in AuthZAttribute. The code is as follows.
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)
{
if (httpContext.Request.IsLocal)
{
return _localReq;
}
else
{
return true;
}
}
}
}
You can see above we are using the constructor AuthZAttribute (bool allowed), which takes a bool value indicating whether the local requests are permitted by taking advantage of the built-in feature of the authorization attribute base class, I only want to show the basic logic of authorization. Now it’s time to implement this attribute to action methods of the controller. Open the HomeController and decorate the Index action method with this Authorize Attribute. The code is given below.
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 you can simply build and then run the application and you will see the following output in the browser. You will prompt to the login page because you are not an authenticated user. It is because of the Authorize attribute.
As I have registered myself with my credentials so there is no need to register again. I will log in with the credentials.
Now, you can see in the figure below, I am logged in.
As you can see, I am logged in and can access the About and Contact page without any need to give login credentials.
Now, put the Authorize attribute to the About action method, as shown below.
Now, build and run the application, and you’ll see the following output in the browser.
But when you click on About link, then the application will redirect your browser to log-in page. Because the About page can only be used by authenticated users. See the picture below.
Now, I’ll write my email and password to access the About page, as shown below.
You can see below, I am redirected to the About page successfully.
Hence you have seen the basic functionality of Authentication and Authorization. One more feature of authorization is, that you can specify specific users to access any action method, decorated with the Authorize attribute.
I am decorating the Contact action method with the Authorize attribute and specifying the user’s email as “[email protected]” 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 = "[email protected]")]
public ActionResult About()
{
ViewBag.Message = "This is the article by Zain.";
return View();
}
[Authorize(Users = "[email protected]")]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
Now, build and run the application. You can see below, that my old credentials are logged in. I am able to access the About page, as shown below.
But when I click on the Contact link, I can’t access the Contact page, because I am not an authenticated user with the email “[email protected]”. I will redirect to the login page, as shown below.
Now, I’ll register myself with a new email and password. The email should be “[email protected]” to access the Contact page.
Now click on Register, and you will automatically be prompted to the index page. So click on the Contact page, and you’ll successfully access it, as shown below.
But now if you click on the About page, you should be prompted to log in page, because you are not authenticated with the email as “[email protected]”. About can only be accessed with this email Id. You can see the login page below while logged in as “[email protected]”.
Hence this is all about authentication and authorization. Now we’ll look at some filters provided in ASP.NET MVC, each with an example. So let’s move towards it.
Filters provided in ASP.NET MVC
ASP.NET MVC provides us with some filters that can be implemented as attributes. These are applicable at the level of action method, the controller, or the whole application.
- AuthorizeAttribute
- HandleErrorAttribute
- OutputCacheAttribute
- RequireHttpsAttribute
AuthorizeAttribute
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.
}
}
As you know, almost every website requires users to log in before using the restricted content of the website. But in some web applications, even when the user is logged in we want to restrict the users to view or modify some specific content. To accomplish this task, you have to use the AuthorizeAttribute class. So when you mark an action method with the AuthorizeAttribute then the access to that action method is restricted to users who are both authenticated and authorized. When the controller is decorated with this attribute then all the action methods of the controller are restricted.
When an unauthorized user tries to access the action method of the controller which is decorated with AuthorizeAttribute, then the user gets a 401 HTTP status code. But if ASP.NET forms authentication is set in the website then the 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 the 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 a total of 5 action methods in which three methods are decorated with an 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 = "[email protected], [email protected]")]
public ActionResult SpecificUserOnly()
{
return View();
}
}
The first two action methods, Index and About, can be accessed by anyone, even anonymous users. The AuthenticatedUsers action method can only be accessed by the users who are properly logged in. The AdministratorsOnly action method can only be accessed to those users who have either the role Admin or Super User. And the SpecificUser action method can only be accessed by those users who have either the name “[email protected]” or “[email protected]”.
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
}
}
After decorating this attribute to an action method, when the action method throws an exception, MVC displays the error view, which is located in the ~/View/Shared folder. There are the following properties of HandleErrorAttribute, which are given below.
- 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.
- View: This 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 the View folder. MVC framework sends information on exceptions in the ViewDictionary object. 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 that 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.
Example
To use HandleErrorAttribute, let’s some changes 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!");
}
Step 2. Go to the 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>
You can see the code below.
The 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="[email protected]")]
public ActionResult About()
{
ViewBag.Message = "This is the article by Zain.";
return View();
}
[Authorize(Users="[email protected]")]
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
public ActionResult CustomException()
{
throw new Exception("Something went wrong!");
}
}
}
And you should add this piece of code into _Layout.cshtml file in the Shared folder is as follows.
<li>@Html.ActionLink("Custom Exception", "CustomException", "Home")</li>
The output of the above line shows the Customer Exception in the navigation bar, as shown below.
Now let’s build and run the application, and go to the /Home/CustomException URL, as shown below.
So when you call the CustomException action method, you can see the above output has an exception.
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 the 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 the code.
- Now simply build and run the application, go to /Home/CustomException URL then you should see the output given below.
Question. I didn’t use the HandleError attribute yet, then how did all this work?
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.
If we put the cursor on FilterConfig and select “Go to definition” option, then you can see the below code.
As you can see, HandleErrorAttribute is already added to the filters collection. So it is already applied to all the controllers and their action methods.
Now if we comment on this line of code, then what happened?
Now, if you build and run the application, and go to /Home/CustomException URL, you should see the following runtime error.
Now, if you want to again handle the error, then you have to decorate the action method with HandleErrorAttribute.
[HandleError]
public ActionResult CustomException()
{
throw new Exception("Something went wrong!");
}
Now you should see the following output in the browser.
Hence, you have seen the use of the HandleError attribute. You can apply it to the controller level if more than one action method of your controller has thrown an exception.
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
}
OutputCacheAttribute is used to store the output of an action method in memory on the web server. For example, if the action method renders a view, that view page will be cached. This cached page will be available to the HTTP requests for some specified time. This can be helpful in saving the time and resources it would take to re-create the result of that action method. Now we are going to take a simple example in which the output of the Test action method of the HomeController will be cached for 10 seconds. There will be a tab for the Test action method in the navigation bar, so when you repeatedly click on the tab, you can see that the page stays cached for 10 seconds.
To use OutputCacheAttribute, let’s some changes 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();
}
Step 2. Go to the 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>
Step 3. Add the View with the name of Test. The code of the Test view is as follows.
@{
ViewBag.Title = "Output";
}
<h2>Output</h2>
<p>
@Html.Encode(ViewData["Message"])
</p>
Output
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 unsecured HTTP request to be re-sent over HTTPS.
To use RequireHttpsAttribute, let’s some changes 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.";
}
When you build and run the application through this URL http://localhost:50491/Home/Force, you should see the following output.
But when we applied the RequireHttps attribute to the Force action method, as shown below in the code, then we couldn’t browse it with HTTP protocol. If we try to browse it with HTTP then it will be redirected to HTTPS URL.
[RequireHttps]
public string Force()
{
return @"This method 'Force' should be accessed only using HTTPS protocol.";
}
Now, build and reload the browser, you can see the change in URL, and the protocol is changed from HTTP to HTTPS. So, the [RequireHttps] attribute, forces an HTTP request to be re-sent over HTTPS.
RequireHttps attribute can be applied on the controller level, in this case, it will apply to all the action methods in that controller.
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, giving feedback, either positive or negative, it will help me to make my articles better and increase my enthusiasm to share my knowledge.