Understanding Filters in .NET Core with Examples

Filters are an essential part of ASP.NET Core, allowing developers to run custom code before or after certain stages in the request processing pipeline. They provide a way to inject logic into the request processing for tasks such as logging, error handling, authentication, and more. This article will explain what filters are, the types of filters available in .NET Core, and how to create and use them with examples.

What are Filters in .NET Core?

Filters in ASP.NET Core are attributes that can be applied to actions, controllers, or globally to modify the way requests are handled. They can be used to add cross-cutting concerns like logging, caching, exception handling, or authorization in a consistent and reusable manner.

Types of Filters in .NET Core

ASP.NET Core provides several built-in filter types, which are executed at different points in the request processing pipeline:

  1. Authorization Filters
    • Run before anything else and are used to ensure the user is authorized to execute the request.
    • Example: [Authorize] attribute.
  2. Resource Filters
    • Run after authorization but before model binding, useful for caching or short-circuiting the request.
    • Example: [ResponseCache] attribute.
  3. Action Filters
    • Execute before and after an action method is called, often used for logging or modifying the result.
    • Example: [ServiceFilter] or [TypeFilter] attribute.
  4. Exception Filters
    • Handle exceptions thrown by the action methods or other filters, allowing custom error responses.
    • Example: [HandleError] attribute in MVC (built-in exception filter).
  5. Result Filters
    • Run before and after the execution of the action result, used to modify the response or the result.
    • Example: Custom result filters for response formatting.

Creating a Custom Filter in .NET Core

Let’s create a custom action filter that logs the execution time of a controller action.

Step 1. Implement the Filter

First, create a class that implements the IActionFilter interface:

using Microsoft.AspNetCore.Mvc.Filters;
using System.Diagnostics;

public class ExecutionTimeLoggerAttribute : Attribute, IActionFilter
{
    private Stopwatch _stopwatch;

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _stopwatch = Stopwatch.StartNew();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        _stopwatch.Stop();
        var executionTime = _stopwatch.ElapsedMilliseconds;
        Debug.WriteLine($"Action {context.ActionDescriptor.DisplayName} executed in {executionTime} ms.");
    }
}

Step 2. Apply the Filter

You can apply this filter to a specific action, a controller, or globally across all controllers.

Applying to a Single Action

[ExecutionTimeLogger]
public IActionResult MyAction()
{
    // Action logic here
    return View();
}

Applying to a Controller

[ExecutionTimeLogger]
public class MyController : Controller
{
    public IActionResult MyAction()
    {
        // Action logic here
        return View();
    }
}

Applying Globally

To apply the filter globally, register it in the Startup.cs file:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add<ExecutionTimeLoggerAttribute>();
    });
}

Using Built-in Filters

ASP.NET Core includes several built-in filters that can be used without writing custom code. Here’s an example of using the [Authorize] and [ResponseCache] filters.

Example

[Authorize]
[ResponseCache(Duration = 60, Location = ResponseCacheLocation.Client)]
public class MyController : Controller
{
    public IActionResult SecureAction()
    {
        // Action logic for authorized users
        return View();
    }
}

Exception Filters Example

To handle exceptions in a custom way, you can create an exception filter:

Step 1. Create the Exception Filter

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

public class CustomExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        context.Result = new ObjectResult("An error occurred.")
        {
            StatusCode = 500
        };
    }
}

Step 2. Register the Exception Filter

Register the filter globally or apply it to specific actions or controllers:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews(options =>
    {
        options.Filters.Add<CustomExceptionFilter>();
    });
}

Conclusion

Filters in .NET Core provide a powerful mechanism to inject cross-cutting concerns into your application. By understanding and using the different types of filters, such as authorization, resource, action, result, and exception filters, you can create cleaner, more maintainable, and reusable code. Whether using built-in filters or creating custom ones, they play a vital role in the request processing pipeline of any ASP.NET Core application.