Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

17 años online

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
martes, 20 de diciembre de 2016
ASP.NET Core MVCComprimir el resultado de la ejecución de una acción puede ser una buena idea para acelerar la descarga y evitar un consumo innecesario de datos, y sobre todo en acciones donde se retorne una cantidad importante de información potencialmente comprimible, como texto plano, JSON o marcado HTML.

Aunque esta tarea es algo que pueden (y suelen) realizar servidores frontales como IIS o Apache, a veces puede ser interesante que sea nuestra aplicación la que se encargue de ello, por ejemplo si estamos ofreciendo servicios directamente desde los servidores Kestrel o WebListener, o si deseamos aplicar algún tipo de compresión personalizada.

Conceptualmente, la tarea de compresión del resultado de una acción es una buena candidata para ser implementada como filtro. Los filtros son capaces de tomar el control antes y después de la ejecución de las acciones, por lo que, al menos en teoría, serían un buen lugar para implementar la lógica de compresión y retorno al cliente de los resultados, y su uso tendría la siguiente pinta:
public class HomeController : Controller
{
    [Compress]
    public IActionResult Test()
    {
        var text = new string('x', 1000000);
        return Content(text);
    }
}
En este post vamos a ver cómo implementar ese filtro [Compress]. Y bueno, aunque implementarlo a mano y desde cero podría tener su gracia, lo que vamos a hacer es aprovechar dos de las últimas e interesantes novedades introducidas recientemente en ASP.NET Core 1.1: el middleware de compresión y la capacidad de utilizar middlewares como filtros de MVC.

Como sabréis, hace pocas semanas se presentó ASP.NET Core 1.1 incluyendo el middleware ResponseCompressionMiddleware en el paquete Nuget Microsoft.AspNetCore.ResponseCompression. Este componente proporciona las funciones de compresión a los resultados de peticiones que circulan por el pipeline.

Sin embargo, dada la propia naturaleza de los middlewares que, por definición, van posicionados en el pipeline de proceso de peticiones de la aplicación, en principio no resultaría sencillo aplicarlo únicamente a una acción o un controlador específico.

Por otra parte, también se presentó el nuevo filtro [MiddlewareFilter] que, como su nombre sugiere, permite utilizar middlewares como filtros de acciones MVC de una forma relativamente sencilla.

Simplificando bastante (podéis ver más detalles aquí), al aplicar este filtro a un controlador o acción se creará un pipeline "virtual" en el contexto de la ejecución del filtro, en el que podremos insertar middlewares que se ejecutarán en los distintos puntos en los que éste toma el control.

Para ello, lo primero que necesitamos es una clase adaptadora, que en la práctica sólo se utilizará para configurar ese pipeline. De hecho, lo único que se exige en ella es que presente un método Configure() similar al que encontramos en la clase Startup de ASP.NET Core, donde aprovecharemos para insertar los middlewares que nos interesen. Por ejemplo, la siguiente clase configura el pipeline añadiendo el middleware ResponseCompressionMiddleware:
public class ResponseCompressionPipeline
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseResponseCompression();
    }
}
Muy importante, antes de que se me olvide: recordad que para usar ResponseCompressionMiddleware es necesario registrar previamente sus servicios, por lo que debemos añadir el siguiente código en el método ConfigureServices() de la clase de inicialización:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddResponseCompression();
    ...
}
Tras ello, ya podríamos aplicar [MiddlewareFilter] de la siguiente forma:
public class HomeController: Controller
{
   [MiddlewareFilter(typeof(ResponseCompressionPipeline))]
   public IActionResult Test()
   {
      var text = new string('x', 1000000);
      return Content(text);
   }
}
Y si ejecutamos la aplicación sobre Kestrel y accedemos a "/Home/Test", veremos que el tamaño de la respuesta se reduce de 977KB a sólo 4.5KB cuando activamos este filtro :)

Pero hey, hablábamos al principio que queríamos utilizar un filtro como [Compress], y no ese churro que comienza con MiddlewareFilter(…) del ejemplo anterior… No pasa nada, podemos implementar ese elegante atributo combinando lo visto anteriormente:
public class CompressAttribute : MiddlewareFilterAttribute
{
    public CompressAttribute() : base(typeof(ResponseCompressionPipeline)) { }
    public class ResponseCompressionPipeline
    {
        public void Configure(IApplicationBuilder app)
        {
            app.UseResponseCompression();
        }
    }
}
¡Y esto es todo! De esta forma tan sencilla hemos creado nuestro filtro [Compress] que podremos aplicar a acciones, controladores, o de forma global.

Publicado en Variable not found.

Aún no hay comentarios, ¡sé el primero!