Learn to use Filters in ASP.NET core from beginning to expert level

Learn to use Filters in ASP.NET core from beginning to expert level

Filters in ASP.NET Core MVC are used to run code before or after certain stages in the request processing pipeline. There are many built-in filters like authorization, logging, caching, exception handling and so on. Filters help to avoid code-duplication across actions.

You can also create custom filters to handle some concerns for your application.

Create the Example Project

I will create an Example project to understand Filters, so use ASP.NET Core Web Application (.NET Core) template to create a new Empty Project and name it ‘Filters’. Remember to select the framework as .NET Core and version as ASP.NET Core 2.0.

Go to the Startup.cs file and enable the MVC framework and other Middleware required for the project:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace Filters
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseStatusCodePages();
            app.UseDeveloperExceptionPage();
            app.UseStaticFiles();
            app.UseMvcWithDefaultRoute();
        }
    }
}

Adding the Bootstrap Package in the bower.json

Create a bower.json file in the root of the application and then add the Bootstrap package to the dependencies section:

{
  "name": "asp.net",
  "private": true,
  "dependencies": {
    "bootstrap": "v4.1.3"
  }
}

On saving the bower.json file the Bootstrap package will be automatically download to the ‘wwwroot/lib’ folder.

Include Built-in Tag Helpers for the Views

In the root folder create a new folder called ‘Views’. Then add the below code to include the built-in tag helpers for the Views:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Built-in Filter – RequireHttps attribute

The RequireHttps attribute is a built-in filter, which when applied to an action method, restricts access to that action to only HTTPS request.

In order to understand the working of the RequireHttps attribute I need to Enable SSL for the project. To enable SSL, right click on the project name in the Solution Explorer and select ‘Properties’.

A new window will open, here click on the Debug tab. Under Web Server Setting click the checkbox that says Enable SSL and click the Ctrl+S to save the changes.

The SSL URL of the project will be different from the non SSL URL. Note it down somewhere as you will need it later on.

See the below image:

enable ssl for project

Next, create a folder called ‘Controllers’ in the root of the project, and add to it a new empty Controller called ‘HomeController.cs’.

Now change the Index action method to return a string as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Filters.Controllers
{
    public class HomeController : Controller
    {
        public string Index()
        {
            return "This is the Index action on the Home controller";
        }
    }
}

Now run your application and you will see the returned string from this action method gets displayed on the browser, see the below image:

action method displayed

To make this action method to be accessed only with Https request I can add the [RequireHttps] attribute to it as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Filters.Controllers
{
    public class HomeController : Controller
    {
        [RequireHttps]
        public string Index()
        {
            return "This is the Index action on the Home controller";
        }
    }
}

Now when you run your application you will see a message – ‘This site can’t be reached’, as shown in the image given below:

action method restricted by requirehttps attribute

This is because you are trying to invoke this action method with a non-https request.

Now simply open the Https based URL in the browser which in my case is https://localhost:44346/ (but yours may be different).

You will see the action method getting invoked as shown by the image below:

action method invoked with an https request

Behind the scene the [RequireHttps] attribute is actually redirecting the non-https URL to the Https based ULR. So a request to the http://localhost:50523/Home/Index is redirected to http://localhost:50523/Home/Index, the change in these 2 URLs is only the ‘https’ while the port is the same.

Since in development the http and https are on different port therefore you see the message ‘This site can’t be reached’. However in a live site, where the site URL does not contains a port, it will work properly because if the request URL is ‘http://www.yogihosting.com’ then you will be redirected to ‘https://www.yogihosting.com’.

The [RequireHttps] built-in filter can also be put on the controller class name which makes it to be applied to every action method contained by the controller.

Example:

[RequireHttps]
public class HomeController : Controller
{
    public string Index()
    {
        return "This is the Index action on the Home controller";
    }

    public string List()
    {
        return "This is the List action on the Home controller";
    }

    public string Hell()
    {
        return "This is the Hello action on the Home controller";
    }
}

Different Types of Filters

Filters implement the IFilterMetadata interface of the Microsoft.AspNetCore.Mvc.Filters namespace.

namespace Microsoft.AspNetCore.Mvc.Filters {
public interface IFilterMetadata { }
}

There are many different types of filters, which are defined in the below table along with the interface that contains them.

Filter Interfaces that contains them Description
Authorization IAuthorizationFilter, IAsyncAuthorizationFilter Used to apply authorization and security policy
Action IActionFilter, IAsyncActionFilter Used to perform a specify work immediately before or after an action method is performed
Result IResultFilter, IAsyncResultFilter Used to perform a specify work immediately before or after the result from an action method is processed
Exception IExceptionFilter, IAsyncExceptionFilter Used to handle exceptions

Notice that each of the filters has 2 interfaces as filters can work both in synchronous and asynchronous manner.

Order of Execution of Filters

Filters are executed in the following order:

1. Authorization filters are the first to execute.
2. Then comes the Action Filters.
3. At the last the Result Filters are executed.

The Exception Filters are executed only when an exception occurs.

Authorization Filters

The Authorization Filters are used for authentication purpose and create security policy. These filters execute before any other filter, and also before the Action method is executed.

Authorization Filters are contained either by IAuthorizationFilter or IAsyncAuthorizationFilter interface.

Definition of IAuthorizationFilter interface:

namespace Microsoft.AspNetCore.Mvc.Filters {
    public interface IAuthorizationFilter : IFilterMetadata {
        void OnAuthorization(AuthorizationFilterContext context);
    }
}

Definition of IAsyncAuthorizationFilter interface:

using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Mvc.Filters {
    public interface IAsyncAuthorizationFilter : IFilterMetadata {
        Task OnAuthorizationAsync(AuthorizationFilterContext context);
    }
}

The IAsyncAuthorizationFilter interface is used for creating Asynchronous Authorization Filters.

The methods OnAuthorization and OnAuthorizationAsync() methods are used to write code so that the filter can authorize the request.

The parameter of the methods – AuthorizationFilterContext context, receives the context data describing the request. The object AuthorizationFilterContext contains a property called ‘Result’ (of type IActionResult) which is set by the authorization filter.

If the Result property is set, then MVC renders the IActionResult instead of invoking the action method.

Creating an Authorization Filter

I will create an Authorization Filter which can be applied to an action method of a Controller (or to the Controller class), and it will restrict the request that are not made with Https protocol.

I would add all my custom filters in a folder called ‘CustomFilters’. So create this folder in the root of the project and add a new class called ‘HttpsOnly.cs’ to it. Add the following code to this class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Filters.CustomFilters
{
    public class HttpsOnly : Attribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            if (!context.HttpContext.Request.IsHttps)
                context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
        }
    }
}

Since the HttpsOnly class will be applied as an attribute, to an action method or controller, therefore it is derived from the Attribute class. Also, since this class will be used to create an Authorization Filter therefore it is derived from the IAuthorizationFilter interface.

The main work is done inside the OnAuthorization method which checks if the request is made from an Https protocol or not.

If the request is not made from Https then I am setting the Result property of the AuthorizationFilterContext object to 403 forbidden. This prevents further execution from happening and provides MVC with a result to return to the client.

Now apply this HttpsOnly filter to the Home Controller’s Index action method:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Filters.CustomFilters;
using Microsoft.AspNetCore.Mvc;

namespace Filters.Controllers
{
    public class HomeController : Controller
    {
        [HttpsOnly]
        public string Index()
        {
            return "This is the Index action on the Home controller";
        }
    }
}

Now run your application and you will see the message Status Code: 403; Forbidden on the browser. The reason being the request coming from a non-https URL.

This is shown by the image below:

status code 403 forbidden

If you open the https version of the URL in the browser then the Authorization filter will find the request is made with Https protocol. So the Result property of the AuthorizationFilterContext object is not set and the Index Action method is executed.

The below image shows the result from the Index Action gets displayed when the request is made from Https protocol:

action method not restricted by authorization filter

This example very well explains the working of an Authorization filter. Next, I will create an Action Filter.

Action Filters

The Action Filters are executed after the Authorization Filters. They are called just before an Action method is called and just after an Action method is finished.

They are derived either from the IActionFilter or asynchronous IAsyncActionFilter interface.

Definition of IActionFilter interface:

namespace Microsoft.AspNetCore.Mvc.Filters {
    public interface IActionFilter : IFilterMetadata {
        void OnActionExecuting(ActionExecutingContext context);
        void OnActionExecuted(ActionExecutedContext context);
    }
}

On applying an Action Filter to an Action method, the OnActionExecuting method is called just before the action method is invoked, and the OnActionExecuted method is called just after the action method is finished executing.

The OnActionExecuting method has a parameter of ActionExecutingContext class type. The important properties of the ActionExecutingContext class are:

Name Description
Controller The name of the controller whose action method is about to be invoked.
Result This property is of type IActionResult. It this property is set a value of type IActionResult then MVC renders the IActionResult instead of invoking the action method.

The OnActionExecuted method has a parameter of ActionExecutedContext class type. The important properties of the ActionExecutedContext class are:

Name Description
Controller The name of the controller whose action method was invoked.
Exception This property contains the Exception that occurred in the Action method.
ExceptionHandled When you set it property to true then the exceptions will not be propagated further.
Result This property returns the IActionResult returned by the action method, and you can change or replace it if you have a need.

Creating an Action Filter

I will now create an Action filter that will measure the number of milliseconds an action method takes to execute. For this I will start a timer in the OnActionExecuting method and stop it in the
OnActionExecuted method.

So create a class called ‘TimeElapsed.cs’ inside the CustomFilters folder and add the following code to it:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;
using System.Text;
using Microsoft.AspNetCore.Mvc;

namespace Filters.CustomFilters
{
    public class TimeElapsed : Attribute, IActionFilter
    {
        private Stopwatch timer;
        public void OnActionExecuting(ActionExecutingContext context)
        {
            timer = Stopwatch.StartNew();
        }
        public void OnActionExecuted(ActionExecutedContext context)
        {
            timer.Stop();
            string result = " Elapsed time: " + $"{timer.Elapsed.TotalMilliseconds} ms";
            IActionResult iActionResult = context.Result;
            ((ObjectResult)iActionResult).Value += result;
        }
    }
}

I have created an object of Stopwatch class to measure the time. I start the time in the OnActionExecuting method and stop the time in the OnActionExecuted method.

Then with the Result property of the ActionExecutedContext object I get the IActionResult returned by the action method. I cast it to ObjectResult type and add the Elapsed time to its value property.

The Value property contains the return value by the action method.

To apply this filter, add the [TimeElapsed] attribute to the Index method of the Home Controller class as shown below:

public class HomeController : Controller
{
    [TimeElapsed]
    public string Index()
    {
        return "This is the Index action on the Home controller";
    }
}

Run your application and you will see the message that will tell the number of milliseconds the action method takes to execute, as shown in the image below:

action filter

The Action Filter can also be created by deriving them from IAsyncActionFilter interface. This interface is given below:

using System.Threading.Tasks;
    namespace Microsoft.AspNetCore.Mvc.Filters {
        public interface IAsyncActionFilter : IFilterMetadata {
            Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next);
    }
} 

There is only 1 method which runs before and after the action method has been executed in this IAsyncActionFilter interface.

The ActionExecutingContext object provides context data to the filter, and the
ActionExectionDelegate object contains the action method (or the next filter) to execute.

Using the IAsyncActionFilter interface I can create the asynchronous version of the TimeElapsed filter as shown in the below code:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Filters.CustomFilters
{
    public class TimeElapsedAsync : Attribute, IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            Stopwatch timer = Stopwatch.StartNew();
            await next();
            timer.Stop();
            string result = "<div>Elapsed time: " + $"{timer.Elapsed.TotalMilliseconds} ms</div>";
            byte[] bytes = Encoding.ASCII.GetBytes(result);
            await context.HttpContext.Response.Body.WriteAsync(bytes, 0, bytes.Length);
        }
    }
}

Result Filters

The Result Filters are executed before and after the result from the Action method is processed. They are executed after the Action Filters.

The Result Filters can be created by implementing the IResultFilter or IAsyncResultFilter interface.

The definition of IResultFilter interface:

namespace Microsoft.AspNetCore.Mvc.Filters {
    public interface IResultFilter : IFilterMetadata {
        void OnResultExecuting(ResultExecutingContext context);
        void OnResultExecuted(ResultExecutedContext context);
    }
} 

The Result Filters have the same pattern like the Action Filters.

The IResultFilter interface has 2 methods – OnResultExecuting & OnResultExecuted. The OnResultExecuting method is called just before the result from the action method is processed, while the OnResultExecuted method is called just after the result from the action method is processed.

The OnResultExecuting method has the parameter of type ResultExecutingContext with properties given in the below table:

Name Description
Controller The name of the controller whose action method is invoked.
Result This property is of type IActionResult and contains the IActionResult object returned by the action method
Cancel Setting this property to true will stop the processing of action result and will give 404 response.

The OnResultExecuted method has the parameter of type ResultExecutedContext with properties given in the below table:

Name Description
Controller The name of the controller whose action method is invoked.
Canceled A read-only property that tells if the request is cancelled
Exception Contains exceptions that are thrown in the action method
ExceptionHandled When this property is set to true that exceptions are not propagated further
Result A read-only property that contains the IActionResult generated by the Action method

Creating a Result Filter

Here I will create a Result Filter that will change the rendered View which invoked by the Action method.

Create a Result Filter class called ‘ChangeView.cs’ inside the ‘CustomFilters’ folder with the code shown below:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Filters.CustomFilters
{
    public class ChangeView : Attribute, IResultFilter
    {
        public void OnResultExecuting(ResultExecutingContext context)
        {
            context.Result = new ViewResult
            {
                ViewName = "List"
            };
        }
        public void OnResultExecuted(ResultExecutedContext context)
        {
        }
    }
}

The Result Filter is a simple one which is just setting the ViewName to ‘List’ in the OnResultExecuting method. This means when this filter is applied to an action method then ‘List’ view will be rendered every time.

Now create a new action method called ‘Message’ in the Home controller as shown below, this action is applied the ‘ChangeView’ filter:

[ChangeView]
public ViewResult Message() => View();

You can clearly see that this action method is invoking the default view which is ‘Message’.

Now create 2 Views in the ‘Views/Shared’ folder. These are:

1. Message View

<h2>Message</h2>

This is Message View

2. List View

<h2>List</h2>

This is List View

Now it’s time to run your application and see what my Result Filter will do. When your application is in the running state, go to the URL – ‘/Home/Message’. You will see the List View got invoked instead of Message View, as shown by the below image:

list view invoked by the result filter

This happens because of the ‘ChangeView’ Result Filter who changed the rendered View to list.

I can recreate my ‘ChangeView’ Result Filter by implementing the asynchronous IAsyncResultFilter interface.

The definition of IAsyncResultFilter is given below:

using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Mvc.Filters {
    public interface IAsyncResultFilter : IFilterMetadata {
        Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next);
    }
}   

Now, add a new class file called ‘ChangeViewAsync’ with the code shown below:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Filters.CustomFilters
{
    public class ChangeViewAsync : Attribute, IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            context.Result = new ViewResult
            {
                ViewName = "List"
            };
            await next();
        }
    }
}

I have implemented the IAsyncResultFilter interface which only contains one method which is OnResultExecutionAsync.

The parameter of type ResultExecutingContext is the one which I use to set the ViewName to ‘List’.

The parameter of type ResultExecutionDelegate is a delegate that asynchronously returns an Microsoft.AspNetCore.Mvc.Filters.ResultExecutedContext indicating the action result or the next result filter has executed.

I had manually invoked the delegate with await next() so that the action result can be rendered.

Now go to the Home controller and change the attribute from [ChangeView] to [ChangeViewAsync]:

[ChangeViewAsync]
public ViewResult Message() => View();

Hybrid Action/Result Filter

A Hybrid Action/Result Filter is the one that is both an Action Filter and a Result Filter. A Hybrid Filter can easily share data from the Action stage to the Result stage.

The simplest way to create a Hybrid Action/Result filter is to inherit ActionFilterAttribute class that implements the interfaces for both kinds of filters.

Create a new class file called ‘HybridActRes.cs’ inside the ‘CustomFilters’ folder with the following code:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;

namespace Filters.CustomFilters
{
    public class HybridActRes : ActionFilterAttribute
    {
        private Stopwatch timer;
        public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            timer = Stopwatch.StartNew();
            await next();
        }

        public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            timer.Stop();
            context.Result = new ViewResult
            {
                ViewName = "ShowTime",
                ViewData= new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                {
                    Model = "Elapsed time: " + $"{timer.Elapsed.TotalMilliseconds} ms"
                }
            };
            await next();
        }
    }
}

This hybrid view has 2 methods:

1. OnActionExecutionAsync – here the stop watch is started.
2. OnResultExecutionAsync – here the stop watch is stopped and the Action method’s ViewResult is changed i.e ViewName is changed to ‘ShowTime’ and Model is filled with a string that shows the elapsed time.

Next, create a ‘List’ Action method inside the Home controller with the code shown below:

[HybridActRes]
public IActionResult List() => View();

The action method has the [HybridActRes] attribute applied to it and invokes the List view with empty model.

Finally create ShowTime View inside the ‘Views/Shared’ folder with the following code:

@model string
<h2>Show Time</h2>

@Model

Now I can check the working of my Hybrid Filter by running the project and visiting the URL – ‘/Home/List’.

You will see the ShowTime View being invoked instead of List View and it shows the elapsed time.

The below image shows it:

hybrid action result filter

So with this hybrid view I am able to do both the functionality in a single file.

Exceptions Filters

Exception Filters allow you to catch exceptions without having to write try & catch block. They implement the IExceptionFilter or IAsyncExceptionFilter interface. The IAsyncExceptionFilter interface is used for creating asynchronous Exception Filters.

The definition of IExceptionFilter interface:

namespace Microsoft.AspNetCore.Mvc.Filters {
    public interface IExceptionFilter : IFilterMetadata {
        void OnException(ExceptionContext context);
    }
}

The definition of IAsyncExceptionFilter interface:

using System.Threading.Tasks;
    namespace Microsoft.AspNetCore.Mvc.Filters {
        public interface IAsyncExceptionFilter : IFilterMetadata {
        Task OnExceptionAsync(ExceptionContext context);
    }
}

For both interfaces, context data is provided through the ExceptionContext class, which is a parameter to the methods – OnException & OnExceptionAsync.

The properties of the ExceptionContext class are given in the table below:

Name Description
Exception The property contains the Exceptions that are thrown
ExceptionDispatchInfo It contains the stack trace details of the exception
ExceptionHandled A read-only property that tells if the exception is handled
Result This property sets the IActionResult that will be used to generate the response

Creating an Exception Filter

Create a class called ‘CatchError.cs’ inside the ‘CustomFilters’ folder. Add the following code to this class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;

namespace Filters.CustomFilters
{
    public class CatchError : Attribute, IExceptionFilter
    {
        public void OnException(ExceptionContext context)
        {
            context.Result = new ViewResult()
            {
                ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                {
                    Model = context.Exception.Message
                }
            };
        }
    }
}

The class ‘CatchError’ is an Exception filter as it implements the IExceptionFilter interface.

The OnException() method will be called whenever there is some error occurred in the Action method that has the [CatchError] attribute.

Inside the OnException method I am just setting the Model with the Exception.Message property. The Model will be shown on the View.

Now create a new action method called ‘Exception’ in the Home Controller, and add the attribute [CatchError] to it:

[CatchError]

public IActionResult Exception(int? id)
{
    if (id == null)
        throw new Exception("Error Id cannot be null");
    else
        return View((object)$"The value is {id}");
}

This action method through an exception if Id value is null else it returns the default View with a string value – ‘The value is {id}’.

Finally create ‘Exception’ view inside the ‘Views/Home’ folder with the following code:

@model string

<h2>Exception</h2>
@Model

You can now check the working of this Exception Filter by running your application and go to the URL – ‘/Home/Exception’. It will show you the message ‘Error Id cannot be null’ as an exception is raised which is captured by the filter.

Now go to the URL – ‘/Home/Exception/5’ where no exception occurred and you will see the message – ‘The value is 5’.

This is illustrated by the below image:

exception filter

You can download the source code using the below link:

Download

Conclusion

You now have the basic knowledge of filters and are ready to use it in your project. In the next tutorial I will cover advanced Filter Topics like – Filters with Dependencies, Global Filters, Order of Execution of Filters & Changing Filter Order.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "WordPress, SEO, jQuery, HTML" and more.