ASP.NET Core Blogs

ASP.NET Core Filters: Detailed Explanation with Examples

Filters in ASP.NET Core allow you to run code before or after specific stages in the request processing pipeline. They provide a way to handle cross-cutting concerns like authorization, caching, exception handling, and logging.

Types of Filters in ASP.NET Core

1. Authorization Filters

Run first and determine whether the user is authorized for the request.

Example:

public class CustomAuthFilter : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (!context.HttpContext.User.Identity.IsAuthenticated)
        {
            context.Result = new UnauthorizedResult();
        }
    }
}

2. Resource Filters

Run after authorization and can short-circuit the pipeline.

Example:

public class CustomResourceFilter : IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        // Before the action executes
        if (!context.HttpContext.Request.Headers.ContainsKey("X-Custom-Header"))
        {
            context.Result = new BadRequestObjectResult("Missing required header");
        }
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
        // After the action executes
    }
}

3. Action Filters

Run immediately before and after an action method is called.

Example:

public class LogActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        Console.WriteLine($"Action {context.ActionDescriptor.DisplayName} is starting");
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        Console.WriteLine($"Action {context.ActionDescriptor.DisplayName} completed");
    }
}

4. Exception Filters

Handle exceptions that occur in the pipeline.

Example:

public class CustomExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        if (context.Exception is UnauthorizedAccessException)
        {
            context.Result = new ObjectResult("Custom error message")
            {
                StatusCode = 403
            };
            context.ExceptionHandled = true;
        }
    }
}

5. Result Filters

Run before and after the execution of action results.

Example:

public class CustomResultFilter : IResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        // Before the result executes
        if (context.Result is ViewResult viewResult)
        {
            viewResult.ViewData["CustomData"] = "Added in filter";
        }
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {
        // After the result executes
    }
}

Registering Filters

You can register filters at different levels:

  1. Globally (applies to all actions):

services.AddControllers(options =>
{
    options.Filters.Add(new CustomAuthFilter());
});
  1. At controller level:

[ServiceFilter(typeof(CustomAuthFilter))]
public class HomeController : Controller
{
    // ...
}
  1. At action level:

[TypeFilter(typeof(LogActionFilter))]
public IActionResult Index()
{
    return View();
}

Differences Between Filters and Middleware in ASP.NET Core

FeatureFiltersMiddleware
ScopeOperate within the MVC pipelineOperate on the entire request pipeline
Execution OrderRun after middleware in the request pipelineRun before filters in the request pipeline
Access to MVC ContextHave access to MVC-specific context (ActionContext, ResultContext)Only have access to HttpContext
LifecycleNew instance per request (unless explicitly registered as singleton)Typically singleton (one instance for all requests)
UsageHandle MVC-specific concerns (action execution, model binding, etc.)Handle lower-level concerns (request/response, headers, compression, etc.)
RegistrationAdded in MVC options or as attributesAdded in Configure method of Startup.cs
When to UseWhen you need MVC context or want to affect MVC-specific behaviorWhen you need to process all requests regardless of MVC

Example of Middleware:

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

    public CustomMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // Before the next middleware
        Console.WriteLine("Middleware - Before next");
        
        await _next(context);
        
        // After the next middleware
        Console.WriteLine("Middleware - After next");
    }
}

// In Startup.cs
public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<CustomMiddleware>();
    // Other middleware
    app.UseMvc();
}

Key Difference in Execution Flow:

  1. Middleware executes first (in the order they’re registered)
  2. Then Authorization Filters
  3. Then Resource Filters
  4. Then Action Filters (before action execution)
  5. Then the action method executes
  6. Then Action Filters (after action execution)
  7. Then Exception Filters (if there’s an exception)
  8. Then Result Filters
  9. Then middleware runs again in reverse order

Filters are more tightly integrated with MVC and have access to MVC-specific context, while middleware operates at a lower level across all requests.

Leave a Reply

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