Middlewares and Filters in .NET

In this post we're going to see what middleware in .NET are as well as filters (FilterAttribute), we'll see their differences and how to implement them;

 

 

1 - What is a middleware in .NET?

Before we can see the differences between middleware and filters, we need to understand what each one is. 

First, let me say that I really dislike the name "middleware", because it doesn't clearly represent where it is located, I mean, yes, in the middle. But personally it doesn't say much to me. 

 

In .NET, a middleware is a class that allows us to manipulate an HTTP request (or response).

 

A middleware acts on every request that reaches our application, therefore it is part of the request pipeline.

And they do the same with the response, but in reverse order.

request pipeline

Since the arrival of .NET Core, the use of middleware is very common, so it is very important to understand the logic behind them and how they work.

It's important to note that order matters, since as I've indicated they are executed one after the other. 

 

Keep in mind that we can create middleware that, under certain conditions, returns a response directly. This would prevent the execution of the middlewares that come after it. 

 

 

1.1 - Middleware examples in ASP.NET Core

We have examples of middlewares: when we create an API with the Visual Studio template, we get the instruction app.UseHttpsRedirection(); which internally adds a middleware to redirect all HTTP requests to HTTPS.

CORS or routing are other very common functionalities which are also implemented through middleware.

 

Or for example, if we have app.UseStaticFiles() enabled, which we usually place first, if the request is "get file" such as a CSS or JavaScript file, we will detect that the file is in the static files folder and return it, without running the rest of the middlewares. 

response from middleware

 

1.2 - Creating middleware in .NET

To create middleware in .NET all we need to do is create a regular class, with the exception of two rules

  1. The constructor must receive RequestDelegate.
  2. A method called Invoke that takes HttpContext as a parameter.
public class EjemploMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {
      await _next(context);
    }
}

And in the class we can do whatever we want, we can even access the dependency container via context.RequestServices.GetService<T>() or via normal dependency injection through the constructor.

 

Now let's add logic. In this example it's simple, we log the time taken by the request, but we can make it as complex as we want.

public class EjemploMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;


    public EjemploMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger(typeof(EjemploMiddleware));
    }

    public async Task Invoke(HttpContext context)
    {
        //Este id es para simular un ID que viene del FrontEnd/Container
        //Con el cual mantenemos "trace" de toda la acción del usuario
        //Antes de la request
        Guid traceId = Guid.NewGuid();
        _logger.LogDebug($"Request {traceId} iniciada");
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();


        await _next(context);

        //Despues de la request
        stopWatch.Stop();

        TimeSpan ts = stopWatch.Elapsed;
        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
        ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
        _logger.LogDebug($"La request {traceId} ha llevado {elapsedTime} ");
    }
}

To activate our middleware, we need to do it in the Configure method inside startup.cs and for that we only need to include the following code.

app.UseMiddleware<EjemploMiddleware>();
  • Note: in Blazor WA we can't use middlewares because there is no pipeline. 

 

And with this, our middleware is activated and working. If we make a request we can see the result:

resultado middleware .net

 

 

2 - What is a filter in .NET

First of all, when we say filter we refer to an ActionFilterAttribute.

And the way it works is similar to middleware, but in this case we use it when we want more control or to be more precise with what we can do.

 

Whereas in middleware we only have access to the HttpContext, in ActionFilterAttribute we have access to much more information, such as the model and of course also to HttpContext.

filterattribute

If we were to put middleware and filter pipelines in an image, the filters pipeline would be after middleware's, but unlike middleware, with filters we can specify where we want to use them.

This is why we say they are more specific, because we may want an endpoint to have a filter or not:

middleware y filtros en la pipeline de .net

As we can see in the image, filter 2 is common to both endpoints, while filter 1 and filter 3 are exclusive to one of the endpoints. 

  • Note: ActionFilterAttribute is not the only filter in .NET, like ExceptionFilter which triggers if there's an exception.

 

 

2.1 - Filter examples in ASP.NET

The most common examples are Authorize, which is an action filter that allows us to restrict access to an endpoint depending on the user or their role.

  • Note: I will be creating a post about this soon. 

Another very common example is OutPutCache which keeps the endpoint's response in cache for the amount of time we specify. 

 

Of course, the filter pipeline works the same way as middleware's: we can return a response from one of them. The most common case is Authorize. With the following directive [Authorize(Policy = "PuedeConsultarUsuarios")] the logged user needs that policy to access the endpoint.

 

 

2.3 - Implementing a filter in ASP.NET

To create a filter is very simple, first we need to create a class that implements any of the filters .NET provides, in our case ActionFilterAttribute.

 

Just as with middleware, we have access to dependency injection from the constructor. 

 

After that, we override the methods we need: OnActionExecuting will run before the endpoint, and OnActionExecuted runs after.

Here's an example:

public class EjemploFiltro : ActionFilterAttribute
{
    private readonly ILogger<EjemploFiltro> _logger;

    public EjemploFiltro(ILogger<EjemploFiltro> logger)
    {
        _logger = logger;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogInformation($"antes del método {context.ActionDescriptor.DisplayName}");
        base.OnActionExecuting(context);
    }

    public override void OnActionExecuted(ActionExecutedContext context)
    {
        _logger.LogInformation($"después del método {context.ActionDescriptor.DisplayName}");
        base.OnActionExecuted(context);
    }
}

In this example, it just logs the method we're executing.

 

 

2.4 - Implementing an Async filter in ASP.NET

If we're accessing an async method, we need to use IAsyncActionFilter and override the OnActionExecutionAsync method.

public class EjemploFiltro : IAsyncActionFilter
{
    private readonly ILogger<EjemploFiltro> _logger;

    public EjemploFiltro(ILogger<EjemploFiltro> logger)
    {
        _logger = logger;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        _logger.LogInformation($"Antes del método {context.ActionDescriptor.DisplayName}");
        await next();
        _logger.LogInformation($"Después del método {context.ActionDescriptor.DisplayName}");

    }
}

As we can see, it looks very similar to middleware.

 

Now we need to add some configuration to use it. First, we must add it to the dependency container 

services.AddScoped<EjemploFiltro>();
  • Note: We need to inject it since we're injecting the logger. 

And then, in the method/endpoint where we want to use it, we indicate it with [ServiceFilter(typeof(EjemploFiltro))] as follows:

[ServiceFilter(typeof(EjemploFiltro))]
[HttpGet("{userName}")]
public async Task<ResultDto<PersonalProfileDto>> Get(string userName)
{
    return (await GetProfile(userName)).MapDto(x=>x);
}
  • Note: If we weren't injecting the logger, we could call the filter directly with `[EjemploFiltro]`.

 

 

Conclusion

In this post we've seen

  • What a middleware is and how to create middlewares in .NET
  • What a Filter attribute is and how to create one in .NET
  • How the request pipeline works in .NET
  • Code examples for Middlewares in .NET
  • Code examples for filters in .NET

 

This post was translated from Spanish. You can see the original one here.
If there is any problem you can add a comment bellow or contact me in the website's contact form

Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2025 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café