ASP.NET  

ASP.NET Core Endpoint Filters: A Complete Developer Guide

Introduction

ASP.NET Core Minimal APIs have become a popular way to build lightweight and high-performance APIs. However, as applications grow, developers often need to perform common tasks before or after an endpoint executes.

Examples include:

  • Request validation

  • Logging

  • Authentication checks

  • Performance monitoring

  • Response modification

Before .NET 7, developers typically used Middleware or custom logic inside endpoints. To simplify these scenarios, Microsoft introduced Endpoint Filters.

Endpoint Filters provide a clean way to run code before and after a Minimal API endpoint executes, making applications easier to maintain and extend.

In this article, you'll learn what Endpoint Filters are, how they work, and how to implement them in ASP.NET Core applications.

What Are Endpoint Filters?

Endpoint Filters allow developers to intercept requests before and after a Minimal API endpoint executes.

Think of them as a pipeline around an endpoint.

Request
   ↓
Endpoint Filter
   ↓
Endpoint
   ↓
Response

This makes it possible to add reusable logic without cluttering endpoint code.

Why Use Endpoint Filters?

Consider a simple endpoint:

app.MapPost("/products",
    (Product product) =>
{
    return Results.Ok(product);
});

Suppose you need validation for multiple endpoints.

Without Endpoint Filters:

Endpoint 1
Validation Logic

Endpoint 2
Validation Logic

Endpoint 3
Validation Logic

The same code gets repeated.

With Endpoint Filters:

Filter
   ↓
Reusable Validation
   ↓
All Endpoints

This improves maintainability.

How Endpoint Filters Work

An Endpoint Filter implements the IEndpointFilter interface.

Example:

public class LoggingFilter
    : IEndpointFilter
{
    public async ValueTask<object?>
    InvokeAsync(
        EndpointFilterInvocationContext context,
        EndpointFilterDelegate next)
    {
        Console.WriteLine(
            "Request Started");

        var result =
            await next(context);

        Console.WriteLine(
            "Request Completed");

        return result;
    }
}

The filter executes code before and after the endpoint.

Registering an Endpoint Filter

Attach the filter to an endpoint.

app.MapGet("/users",
    () => Results.Ok("Users"))
    .AddEndpointFilter<LoggingFilter>();

When the endpoint executes:

Request Started
      ↓
Endpoint Executes
      ↓
Request Completed

The filter automatically runs.

Using Endpoint Filters for Validation

A common use case is request validation.

Example:

public class ValidationFilter
    : IEndpointFilter
{
    public async ValueTask<object?>
    InvokeAsync(
        EndpointFilterInvocationContext context,
        EndpointFilterDelegate next)
    {
        var product =
            context.GetArgument<Product>(0);

        if (string.IsNullOrWhiteSpace(
            product.Name))
        {
            return Results.BadRequest(
                "Product Name Required");
        }

        return await next(context);
    }
}

Register:

app.MapPost("/products",
    (Product product) =>
{
    return Results.Ok(product);
})
.AddEndpointFilter<ValidationFilter>();

The endpoint remains clean while validation logic is centralized.

Inline Endpoint Filters

For simple scenarios, you can define filters directly.

Example:

app.MapGet("/hello",
    () => "Hello World")
.AddEndpointFilter(
    async (context, next) =>
{
    Console.WriteLine("Before");

    var result =
        await next(context);

    Console.WriteLine("After");

    return result;
});

This is useful for small, endpoint-specific logic.

Real-World Example

Imagine an e-commerce API.

Endpoints:

  • Create Product

  • Update Product

  • Delete Product

Each endpoint requires:

  • Logging

  • Validation

  • Request tracking

Instead of repeating logic:

Endpoint Filter
      ↓
Shared Functionality
      ↓
Multiple Endpoints

This reduces code duplication significantly.

Endpoint Filters vs Middleware

Many developers wonder when to use Middleware versus Endpoint Filters.

Middleware

Works globally.

Request
   ↓
Middleware
   ↓
All Endpoints

Best for:

  • Authentication

  • Exception handling

  • Global logging

Endpoint Filters

Work at endpoint level.

Request
   ↓
Endpoint Filter
   ↓
Specific Endpoint

Best for:

  • Validation

  • Endpoint-specific logging

  • Business rules

Use the right tool for the right requirement.

Advantages of Endpoint Filters

Endpoint Filters provide several benefits:

  • Cleaner endpoint code

  • Reusable logic

  • Better maintainability

  • Reduced duplication

  • Easy validation implementation

  • Improved separation of concerns

These advantages make Minimal APIs easier to manage.

Best Practices

When using Endpoint Filters:

  • Keep filters focused on a single responsibility.

  • Use filters for endpoint-specific logic.

  • Avoid complex business logic inside filters.

  • Use Middleware for global concerns.

  • Reuse filters across related endpoints.

  • Keep endpoint methods clean and readable.

Following these practices improves application architecture.

Conclusion

Endpoint Filters are a powerful addition to ASP.NET Core Minimal APIs. They allow developers to execute logic before and after endpoint execution, making it easier to implement validation, logging, monitoring, and other cross-cutting concerns.

By moving reusable functionality into filters, applications become cleaner, more maintainable, and easier to scale. Whether you're building small APIs or enterprise applications, Endpoint Filters provide a flexible way to organize endpoint-specific behavior without cluttering business logic.