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 are used to run code before or after certain stages in the request processing pipeline. There are many built-in filters for authorization, logging, caching, exception handling and so on. Filters also help to avoid code-duplication across action methods.

You can also create custom filters to handle concerns for your application in the way you want.

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 as Filters. Remember to select the framework as .NET Core and version as ASP.NET Core 3.1.

Next, go to the Startup.cs file and enable the MVC framework and other Middlewares required for the project, see the below highlighted code.

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;
using Microsoft.Extensions.Hosting;

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

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Adding the Bootstrap Package

Bootstrap is a  CSS framework directed at responsive, mobile-first front-end web development. I will use it to create a nice looking UI. So install the Bootstrap package in your project. You can check How to Install Bootstrap Package in ASP.NET Core Application in Visual Studio

Include Built-in Tag Helpers for the Views

In the root folder of your project, create a new folder called Views. Then add Razor View Imports file inside the Views folder to include the built-in tag helpers for the Views. The code which you have to add to this file is shown below.

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Built-in Filter – [RequireHttps] attribute

The [RequireHttps] attribute is a built-in filter which on applying to an action method restricts only HTTPS request to invoke it.

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, un-check 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.

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 mostly white screen with 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.

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 https://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 on the live site, where the site URL does not contains a port, it will work properly because if the requested 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.

Learn the concept of Different types of View methods that tell MVC how to render a particular View.

Example:

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

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, important ones 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 filter has 2 interfaces (Synchronous & Asynchronous) 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 authorization purpose and creating security policy. These filters execute before any other filter and even 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 called OnAuthorization() and OnAuthorizationAsync() are used to write code so that the filter can authorize incoming requests.

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

If the Result property is set then ASP.NET Core renders the IActionResult instead of invoking the action method.

Cookie authentication uses HTTP cookies to authenticate client requests and maintain session information. Learn How to Implement Cookie Authentication in ASP.NET Core

Creating an Authorization Filter

I will now create an Authorization Filter which can be applied to an action method or to the Controller class itself. This filter will restrict the requests that are not made with Https protocol.

I would add all my custom filters including this one 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. Next add the following code to this class:

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

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 the 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 ASP.NET Core 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 and just after an Action method is called.

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 has 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. If 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.
Are you deploying APIs on live server then you need to implement CORS else the browser will stop all client requests made to the APIs. Therefore read this tutorial – How to Enable Cross-Origin Requests (CORS) in ASP.NET Core

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 System.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

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.e. context.Result) I get the IActionResult returned by the action method. Note that it contains the string value returned by the action which is – This is the Index action on the Home controller.

Finally I cast it to ObjectResult type and add the Elapsed time to it’s value property.

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 be executed.

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.Linq;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Text;
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 then 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 when invoked by the Action method.

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

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

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 above Result Filter is a simple one as it just sets 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 with 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. So run the project and go to the URL – /Home/Message. You will see the List View gets 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.

Now 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] for this to be applied on the action method.

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

Hybrid Action/Result Filter

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

The simplest way to create a Hybrid Action / Result filter is to inherit the 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 filter has 2 methods:

  • 1. OnActionExecutionAsync – here the stop watch is starting.
  • 2. OnResultExecutionAsync – here the stop watch is stopping and the Action method’s ViewResult 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 a view called ShowTime inside the Views ➤ Shared folder with the following code:

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

Now I can check the working of this 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 filter I am able to do both the functionality in a single file.

Exceptions Filters

Exception Filters allow catching 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 called 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 having [CatchError] attribute.

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

Learn ASP.NET Core Built-in Tag Helpers which are very useful in working with .net projects.

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 raises 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 going 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 this filter.

Now go to the URL – /Home/Exception/5 where no exception occurs 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 "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.