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, 3 de febrero de 2015
ASP.NET CoreEl célebre Global.asax ha estado con nosotros durante más de diez años, y, junto con el Web.config y algunos otros, ha sido uno de los archivos que encontrábamos siempre en la carpeta raíz de toda aplicación web basada en ASP.NET.

Durante lustros lo hemos usado para introducir código de inicialización de nuestras aplicaciones y para tomar el control en distintos momentos del proceso de las peticiones: al recibirse una solicitud, al retornar la respuesta, al comenzar una sesión, al finalizarla, al autenticar las peticiones… en fin, que es fácil echarlo de menos cuando abrimos o creamos nuestra primera aplicación ASP.NET Core.

Pero como ya hemos comentado por aquí en alguna ocasión, con ASP.NET Core nuestro entrañable Global.asax desaparece para no volver, en primer lugar porque la propia clase HttpApplication, donde se originan esos eventos en los que introducíamos nuestro código, es parte inseparable de System.Web, y ya sabemos que uno de los principales objetivos de ASP.NET Core es desligarse por completo de este pesado lastre. Pero hay algunos motivos estructurales más, que veremos a continuación.


En ASP.NET Core las peticiones son conducidas a través de una tubería (conocida como pipeline), por donde pasarán tanto los datos enviados en la petición como la respuesta enviada de vuelta al cliente. En este pipeline encontraremos “enganchados” una serie de componentes, llamados middlewares, que tienen la capacidad de observar, capturar, procesar, e incluso alterar el contenido de las solicitudes y las respuestas conforme van pasando por el interior del pipeline.

Hay middlewares destinados a realizar tareas relativamente pequeñas como almacenar cierta información de la petición o respuesta en un log o mostrar páginas de error personalizadas, pero en el pipeline también podemos encontrar componentes de mucho más calado e incluso frameworks completos, como el propio framework MVC o SignalR.

Pero lo interesante es que, a diferencia del monolítico ASP.NET clásico (4.x y anteriores), estos middlewares son todos opcionales y en nuestras aplicaciones instalaremos sólo los que vayamos a necesitar. En el siguiente diagrama se muestra un ejemplo de pipeline configurado con tres middlewares destinados a una tarea específica (logging, tratamiento de errores y autorización), el framework MVC, y finalmente nuestra aplicación:
ASP.NET 5 pipeline example
Los middlewares observan continuamente toda la información que circula a través del pipeline en sentido ascendente (peticiones) y descendente (respuestas) y a cada uno de ellos, en el orden en que se encuentran, se les da la oportunidad de realizar las siguientes acciones:
  • Ejecutar una tarea y después permitir que la petición continúe su andadura por el pipeline. Por ejemplo, un middleware puede guardar en un log algunos datos de la petición y pasar el control al siguiente módulo en el pipeline, de forma que el proceso siga adelante.
     
  • Procesar directamente la petición y retornar la respuesta, como ocurriría con el framework MVC que vemos al final del pipeline en el diagrama anterior. La petición llegaría al mismo, éste ejecutaría nuestra aplicación, y el resultado sería enviado de vuelta, de nuevo a través del pipeline para que otros middlewares puedan procesarlo.
     
  • Cortocircuitar el proceso y enviar un retorno personalizado. Por ejemplo, el middleware de autorización podría realizar una comprobación de seguridad sobre la petición, y llegado el caso, directamente retornara una redirección a la página de login sin dar la posibilidad de que se ejecuten otros módulos posicionados posteriormente en el pipeline.
     
  • Dejar que el resto de módulos se ejecuten y tomar el control cuando pase la  respuesta a la petición, observándola, post-procesándola, o sustituyéndola por otra. Por ejemplo, en el diagrama anterior tendríamos un middleware de gestión de errores examinando los resultados retornados al cliente, sustituyendo las respuestas con un HTTP 500 por una página de error personalizada.
Observad que todo va enganchado al pipeline y actúa de la misma forma, incluso los frameworks de cierto tamaño como ASP.NET Core MVC. Bueno, salvo nuestra aplicación, porque está construida sobre un marco de trabajo que nos aísla de detalles de menor nivel.

Muy bien, ¿pero y qué tiene que ver todo esto con mi desaparecido Global.asax? Bueno, pues un poco sí ;)

En primer lugar, este enfoque requiere de la existencia de un punto de arranque de la aplicación, entre otras cosas porque en algún sitio hay que configurar el pipeline, es decir, introducir en él los middlewares que vamos a usar en nuestra aplicación.

Y ahí es donde entra en juego la clase Startup, introducida como clase de inicialización de OWIN/Katana en MVC 5, Web API 2 o SignalR 2, como el nuevo punto de entrada de nuestras aplicaciones web ASP.NET Core. El siguiente código muestra una clase Startup básica, cuyo método Configure(), invocado automáticamente por la infraestructura de ASP.NET Core, añade al pipeline un middleware para gestionar errores, otro para permitir el acceso a contenidos estáticos del sistema de archivos (css, js, html...), y finalmente el framework MVC:



Por tanto, si queremos incluir código que se ejecute al arrancar la aplicación, la clase Startup, y más concretamente su método Configure(), será el sitio correcto para ello. De esta forma supliremos la ausencia del Global.asax y su evento Application_Start(). Por cierto, la representación gráfica del pipeline configurado anteriormente sería algo así:
ASP.NET 5 pipeline example

Por otra parte, esta estructura modular en la que se basa el nuevo funcionamiento de ASP.NET Core, el pipeline en el que cada aplicación instala los middlewares que necesita, hace que el Global.asax o un componente similar que concentre la mayoría de eventos generados durante el proceso de las peticiones deje totalmente de tener sentido, porque no existe un punto centralizado en el que dichos eventos sean gestionados.

Por ejemplo, si se produce un error en algún momento del proceso de la petición, será un middleware el encargado de procesarlo. Si un usuario inicia una sesión (el clásico Session_Start()del Global.asax) será el middleware encargado de proveer el servicio de sesión el que deba informar de estos eventos, o si queremos simplemente realizar alguna acción al principio y al final de cada petición, tendremos que implementar un middleware y posicionarlo al comienzo del pipeline, para que procese antes que otros las peticiones entrantes y procese después de todos los demás los resultados retornados.

Así, el código que introducíamos anteriormente en el Global.asax en eventos como los clásicos Application_BeginRequest() o Application_Error() pasarán a ser middlewares personalizados, o configuraciones específicas de los middlewares que permitan especificar callbacks cuando alguno de los eventos se produzcan.

En resumen, aunque seguro que alguna vez echaremos de menos las soluciones tan sencillas y directas que nos ofrecía el Global.asax en distintos escenarios, con ASP.NET Core vamos a poder continuar haciendo lo mismo, incluso mucho más, gracias a su arquitectura modular.


Publicado en Variable not found.

2 Comentarios:

Alberto Baigorria dijo...

Muy bien explicado.
Saludos desde Santa Cruz, Bolivia.

José María Aguilar dijo...

Muchas gracias!!