Middleware en ASPNET Core Personalizado

portada

Al crear un nuevo proyecto web con ASPNET Core es imposible que no usemos mínimo un middleware, ya sea, para configurar la base de datos, para establecer la autenticación, para establecer el uso de archivos estáticos o simplemente para utilizar el patrón MVC. En este articulo veremos como crear un middleware en ASPNET Core.

¿Que es un middleware?

Un middleware es un programa que se ejecuta entre el sistema operativo, tal vez de un servidor, y las aplicaciones que se ejecutan en él. Es una capa oculta de abstracción  para permitir la comunicación y la administración entre otras aplicaciones distribuidas. También se le suelen decir tuberías (plumbing), porque conecta dos aplicaciones para que se puedan pasar fácilmente datos y bases de datos por una “canalización”.

Pero un middleware en ASPNET Core no se ejecuta en programa aparte, es más, como dije al principio, en ASPNET Core estamos llenos de middlewares.

Un middleware en ASPNET Core es una porción de código que se incrusta en el ciclo de vida de un contexto HTTP, donde se puede ejecutar código antes y después de que la petición HTTP entre en un controlador, de esta manera, poder controlar las solicitudes y las respuestas.

Comparación middleware con acueducto
Comparación middleware con acueducto

¿Como me doy cuenta si estoy usando un middleware?

Bastante sencillo, en la clase Startup es donde se suelen especificar los middleware. Los middlewares se suelen usar a partir de métodos de extensión, cuya nomenclatura empieza con ‘Use’.

Por ejemplo, en el siguiente código podemos observar que se utilizan 3 middlewares que se llaman en el método Configure. Primero se llama a UseHttpsRedirection, que se utiliza para que toda petición HTTP recibida sea enviada con el esquema HTTPS. Segundo, tenemos a UseStaticFiles, que se utiliza cuando tenemos archivos en la carpeta wwwroot y queremos acceder a ellos mediante una url, por ejemplo https://localhost/miarchivoestatico.txt. El tercer middleware que hay en el código es UseMvc, nunca vi un proyecto sin esta linea de código y es porque sin esto no funcionarían los controladores, ya que se utiliza para poder utilizar las urls basadas en los nombres de los controladores y acciones, por ejemplo https://localhost/controller/action.


public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

        services.AddDbContext<MovieContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("MovieDb")));
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseMvc();
    }
}

Si vieron en el método ConfigureServices, está el método UseSqlServer pero este no es un middleware porque, aunque comparten la nomenclatura de usar Use, ese método es para indicar que se usa SqlServer en vez de MySql o de otro motor de base de datos. Además, los middlewares se establecen en el método Configure.

Crear un middleware personalizado en ASPNET Core

Middleware Crudo

La manera más cruda o más directa es utilizando el método Use. Este método recibe como parámetro un Func asincrónico que recibe 2 parámetros: el contexto HTTP (context) y otro método que sera la ejecución del siguiente middleware en ASPNET Core (next).


public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                var culture = new CultureInfo(cultureQuery);

                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;
            }

            // Call the next delegate/middleware in the pipeline
            await next();

            Console.WriteLine("Response With StatusCode: " + context.Response.StatusCode);
        });
    }

En el código anterior vemos como hacer un código que se ejecute cuando se recibe una solicitud y otro código cuando vamos a devolver una respuesta, donde en el medio de ambos momentos, esperamos a que se termine de ejecutar el siguiente middleware con next , que podría ser UseMVC.

Un middleware para crear otro middleware

No se suelen crear middlewares, como el ejemplo anterior, de esa manera tan cruda, si no, que se utiliza el método de extensión UseMiddleware.

UseMiddleware es un método genérico que necesita de una clase que contenga 2 características:

  • Un constructor público con un parámetro de tipo RequestDelegate.
  • Un método asincrónico que se llame “Invoke” o “InvokeAsync“. Este método recibirá como parámetro un HttpContext y devolverá un Task.

public class CustomMiddleware
    {
        private readonly RequestDelegate _next;

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

        public async Task InvokeAsync(HttpContext context)
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                var culture = new CultureInfo(cultureQuery);

                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;
            }

            // Call the next delegate/middleware in the pipeline
            await next(context);

            Console.WriteLine("Response With StatusCode: " + context.Response.StatusCode);
        }
    }

Ahora que ya tenemos la clase de nuestro middleware podemos usarla en la clase Startup con el método UseMiddleware.


public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseMiddleware<CustomMiddleware>();
    }
}

Nuestro método de extensión

Si queremos hacerlo más prolijo todavía, podríamos hacer nuestro propio método de extensión para utilizar el middleware que creamos.


public static class CustomMiddlewareExtensions
    {
        public static IApplicationBuilder UseCustomMiddleware(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<CustomMiddleware>();
        }
    }

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseCustomMiddleware();
    }
}

Conclusión

ASPNET Core trae una gran cantidad de middlewares para usar en nuestros proyectos pero puede que necesitemos, por ejemplo, crear un log con cada solicitud y respuesta, crear un proxy inverso para aumentar la seguridad o para mapear los headers que envía una aplicación especifica a un objeto propio. Para todo esto necesitaremos crear un middleware en ASPNET Core personalizado.

Deja un comentario

Tu dirección de correo electrónico no será publicada.