Skip to content

Built-in Filter in ASP.NET MVC

Filters provide a simple and elegant way to implement cross-cutting concerns in your ASP.NET MVC application. Filter achieve this by injecting code into the request processing. Examples of cross-cutting concerns are logging and authorization.

Five Types of Filter

ASP.NET MVC has five types of filter built-in which allow you to implement additional logic during the request processing.

Filter TypeInterfaceDefault ImplementationDescription
ActionIActionFilterActionFilterAttributeRuns before and after the action method
AuthenticationIAuthenticationFilterNoneRuns first, before any other filters or the
action method and can run again after
the authorization filters
AuthorizationIAuthorizationFilterAuthorizeAttributeRuns second, after authentication, but
before any other filters or the action method
ExceptionIExceptionFilterHandleErrorAttributeRuns only if another filter, the action method,
or the action result throws an exception
ResultIResultFilterActionFilterAttributeRuns before and after the action method

Before the framework invokes an action, it inspects the method definition to see if it has attributes. If the framework finds one, the methods of this attribute are invoked. As you can see, the ActionFilterAttribute is implemented by IActionFilter and IResultFilter. This class is abstract and enforces you to implement it. The AuthorizeAttribute and HandleErrorAttribute classes already contain useful features therefore you don’t have to derive from them.

Applying a Filter to an Action or Controller

It is possible to apply one or more filters to an action or controller. A filter which is often used is the Authorize attribute. If the Authorize attribute is applied to an action, only users which are logged in can invoke this action. If the attribute is applied to the controller, it applies to all actions.

Apply filter to action and controller
Apply filter to action and controller

On the example above, I applied the Authorize attribute to the controller which means that every action of this controller can be invoked only by logged in users. Additionally, I applied the attribute to the DoAdminStuff and set the Roles to Admin which means that only users which have the admin role are allowed to invoke this action. This example also shows that some attributes can have a parameter to specify the action.

Applying Authorization Filters

In the last section, I already used one of the two attributes of the Authorize attribute. The available properties are: 

NameDescription
UsersComma-separated usernames which are allowed
RolesComma-separated role names

If several roles are declared, then the user must have at least one of these roles.

Applying Authentication Filters

Authentication filters run before any other filter and can also run after an action has been executed but before the ActionResult is processed.

The IAuthenticationFilter Interface

The Authentication filter implements IAuthenticationFilter which implements two methods:

  • void OnAuthentication(AuthenticationContext context);
  • void OnAuthenticationChallenge(AuthenticationChallengeContext context);

The OnAuthenticationChallenge method is invoked whenever a request fails the authentication or authorization process. The parameter is an AuthenticationChallengeContext object which is derived from ControllerContext. The AuthenticationChallengeContext class has two useful properties:

NameDescription
ActionDescriptorReturns an ActionDescriptor that describes the action method to which the filter has been applied
ResultSets an ActionResult that expresses the result of the authentication challenge

Applying Exception Filters

Exception filters are only executed if an unhandled exception has been thrown when invoking an action. An exception can be thrown by:

  • Another filter
  • The action itself
  • During the action result execution

Microsoft provides the HandleErrorAttribute for exception handling. This class implements the IExceptionFilter interface. The HandleErrorAttribute class has three properties:

NameTypeDescription
ExceptionTypeTypeThe exception type handled by this filter. It will also handle exception types that inherit from the specified value but will ignore all others. The default value is System.Exception, which means that, by default, it will handle all standard exceptions.
ViewstringThe name of the view template that this filter renders. If you do not specify a value, it takes  a default value of Error, so by default, it renders /Views/<currentControllerName>/ Error.cshtml or /Views/Shared/Error.cshtml.
MasterstringThe name of the layout used when rendering this filter’s view. If you do not specify a value, the view uses its default layout page.

As summary: When an unhandled exception of the type specified by ExceptionType is encountered, this filter will render the view specified by the View property

If an exception occurs in your development environment, you will get the famous yellow screen of death. To prevent this from happening, you have to set the customsError attribute to the web.config file.

CustommError in web.config
CustommError in web.config

The customError attribute redirects the request to the location specified at the defaultRedirect attribute. The default value for the mode attribute is RemoteOnly, which means that all local requests see the yellow screen of death.

Applying the HandleError attribute

Applying the HandleError attribute to an action enables you to prevent the application from crashing and also enables you to provide some useful error message and help to the user. You can specify an ExceptionType and then send the request to a specific view and provide some information about what went wrong.

Apply HandleError on an action
Apply HandleError on an action

On the screenshot above, you can see two different versions of how to use the HandleError attribute. The first line with the attribute only would redirect to /Error/ErrorMessage because I defined this destination in the defaultRedirect attribute in the web.config. This page can only show a generic error message which might not help the user at all.

Therefore you can also specify which exception might happen and then redirect the request to a specific view. In the example above, I redirect all ArgumentOutOfRangeException to the ErrorMessage view. This view can be either in the view folder of the controller or in the shared view folder.

Displaying information with the HandleErrorInfo view model

The HandleError attribute passes the HandleErrorInfo view model to your view. The properties of the HandleErrorInfo view model are:

NameTypeDescription
ActionNamestringReturns the name of the action method that generated the exception
ControllerNamestringReturns the name of the controller that generated the exception
ExceptionExceptionReturns the exception

In the ErrorMessage view, I can use this view model to give the user a proper error description and provide some help to solve the problem.

Hepful error message in the view
Helpful error message in the view

I know that my error message is not the best and I bet that you can come up with a better one. I also provided a link, so the user can easily return to the page where he came from.

Applying Action Filters

Action filters can be used for anything. I use them for performance checks to find problems with the execution of actions.

Using the IActionFilter interface

The IActionFilter interface has two methods:

  • void OnActionExecuting(ActionExecutingContext filterContext)
  • void OnActionExecuted(ActionExecutedContext filterContext)

The OnActionExecuting method is called before an action method is invoked. The parameter, ActionExecutingContext has two properties:

NameTypeDescription
ActionDescriptorActionDescriptorProvides details of the action method
ResultActionResultThe result for the action method. A filter can cancel the request by setting this property to a non-null value

The OnActionExecuted method is called after the action is completed and has 5 properties:

NameTypeDescription
ActionDescriptorActionDescriptorProvides details of the action method
CanceledboolReturns true if the action has been canceled by another filter
ExceptionExceptionReturns an exception thrown by another filter or by the action method
ExceptionHandledboolReturns true if the exception has been handled
ResultActionResultThe result for the action method; a filter can cancel the request by setting this property to a non-null value

Implementing an Action Filter

I created a new class called MyActionAttribute which derives from FilterAttribute and IActionFilter. In the OnActionExecuting method, I check if the browser is Chrome. If the request comes from Chrome, I return an HttpUnauthorizedResult. Again, this is not the most useful implementation but I think you get what you can do with this method. For now, I don’t implement anything in the OnActionExecuted method. This is no problem. Just be careful because Visual Studio throws a NotImplementedException if you let Visual Studio create the method.

The action filter class implementation
The action filter class implementation

To use my new filter, I apply it to the CheckFilter action. Note that you don’t have to write MyActionAttribute when applying it as attribute. MyAction is enough.

Applying the action filter attribute to an action
Applying the action filter attribute to an action

When you call this action from Chrome, you can see that the access is denied for the user.

Result of the action filter
Result of the action filter

 

Unauthorized result in Chrome
Unauthorized result in Chrome

Implementing the OnActionExecutedMethod

As I already mentioned, I often use action filter to measure the execution time of an action. To do that, I start a Stopwatch in the OnActionExecuting method and stop it in the OnActionExecuted method. Afterwards, I print the execution time.

Implementation of the PerformanceAction attribute
Implementation of the PerformanceAction attribute

To see different results, I added Thread.Sleep with a random number, so that the execution will take somewhere between some milliseconds and two seconds.

Applying the PerformanceAction attribute
Applying the PerformanceAction attribute

The print of the execution time is printed before the content of the action because the action filter is executed before the result of the action is processed.

Result of performance test with the action filter
Result of performance test with the action filter

Applying Result Filters

The IResultFilter which is implemented by result filters has two methods:

  • void OnResultExecuting(ResultExecutingContext filterContext)
  • void OnResultExecuted(ResultExecutedContext filterContext)

The OnResultExecuting method is called after an action has returned an action result but before this result is executed. The OnResultExecuted method is called after the action result is executed. The ResultExecutingContext and ResultExecutedContext parameter has the same properties as the action filter parameter and also have the same effects.

Implementing a Result Filter

To demonstrate how the result filter works, I repeat the performance test but this time I measure the time between the start and the end of the execution of the ActionResult. To do that, I implement the IResultFilter and work with the OnResultExecuting and OnResultExecuted method.

Implementation of the ResultAction attribute
Implementation of the ResultAction attribute

The next step is applying the filter to an action and call the action to see the result.

Applying the result filter attribute to an action
Applying the result filter attribute to an action

When you look at the output, you see a difference in the result of the action filter output. The print of the measured time is beneath the output of the action. This behavior is caused by the fact that the result filter is processed after the ActionResult. Therefore the result is printed and then afterward the measured time is added.

Result of performance test with the action filter
Result of performance test with the action filter

Filtering without Filter

In the previous examples, I showed how to create implementations of filters by implementing the desired interface. The Controller class already implements the IAuthenticationFilter, IAuthorizationFilter, IActionFilter, IResultFilter, and IExceptionFilter interfaces. It also provides empty virtual implementations for each of the methods. Knowing this, you can override the desired methods directly in the controller and achieve the same outcome as the filter classes did.

Applying filtering in a controller without filter attributes
Applying filtering in a controller without filter attributes

If you call the Index action of the FilteringWithoutFilter controller, you will see the same result as previously with the attributes.

 

Result of performance test with the action and result filter
Result of performance test with the action and result filter

I have to admit that I am not a big fan of this approach. The big advantage of ASP.NET MVC is Separation of Concerns. When using filtering within a controller, you lose this advantage. The only time when it might make sense to use filtering directly in a controller is when this class is a base class for other controllers.

I recommend using the attribute approach.

Simply combining Action and Result Filter

If you look closely, you can see that I combine the action filter method OnActionExecuting and the result filter method OnResultExecuted. You can do this yourself by implementing the IActionFilter and IResultFilter interface or by deriving from ActionFilterAttribute which implements both interfaces. The advantage of deriving from ActionFilterAttribute is that you don’t have empty methods which are not implemented.

Applying Global Filters

If you want to apply filter to all your actions, you can use global filters. If you are using the MVC template, the framework already creates the FilterConfig.cs file under the App_Start folder. Since I didn’t use the template, I create the file myself. This class has one static method, RegisterGlobalFilters. The FilterConfig.cs is pretty similar to the RouteConfig.cs. To add a new filter, add it to the filters collection with add.

Register a filter globally in FilterConfig.cs
Register a filter globally in FilterConfig.cs

Note that the namespace is Filter, not Filter.App_Start.

The HandleErrorAttribute will always be defined as global filter in ASP.NET MVC. It is not mandatory to define the HandleErrorAttribute as global filter but it is the default exception handling and will render the /Views/Shared/Error.cshtml view if an exception happens.

To register a filter a, you have to pass an instance of the filter class. The name contains the Attribute prefix. If you use the class as attribute, you can omit the Attribute prefix. Additionally, you have to add the RegisterGlobalFilters call in the Global.asx file.

Content of the Global.asx
Content of the Global.asx

Conclusion

In this post, I showed all five types of built-in filters in the ASP.NET MVC framework and discussed how to use them to address cross-cutting concerns effectively. These filters help you to extend the logic of your controller and actions while a request is processed.

For more details about how built-in filters work, I highly recommend the books Pro ASP.NET MVC 5 and Pro ASP.NET MVC 5 Plattform.

You can find the source code on GitHub.

Published inASP.NET MVC / Core

Be First to Comment

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    RSS
    Follow by Email
    LinkedIn
    Share