martes, 12 de noviembre de 2013
En todos los posts anteriores hemos visto cómo usar middlewares asumiendo que su ejecución era puramente secuencial y en el mismo orden en el que habían sido añadidos al pipeline.
Sin embargo, cuando sabemos que nuestra aplicación va a correr sobre un host ASP.NET/IIS, utilizando el adaptador disponible en el paquete
En este post vamos a ver cómo funciona este mecanismo pero, primero, permitid que recuerde a los que acabáis de llegar los posts anteriores de la serie:
La diferencia es que los primeros actúan sobre el pipeline de OWIN y los segundos sobre el pipeline de IIS. En este último caso, la lógica de proceso de los módulos se implementa en handlers de los eventos que representan los principales estados por los que pasa una petición:
En siguiente ejemplo añadiríamos los middlewares
Un detalle importante es que el orden en que llamamos a
El módulo HTTP es el siguiente:
Observad que primero se ha ejecutado el módulo HTTP porque los middlewares están asociados por defecto a una fase posterior del proceso del pipeline. A partir de ahí, se van ejecutando sucesivamente en sentido ascendente hasta llegar al módulo final, que retorna el valor y continúa la ejecución de los módulos, ahora en orden inverso.
Utilizamos ahora
Como se observa, a primera llamada a
En definitiva, lo interesante de todo esto es que podemos utilizar componentes middleware en aplicaciones ASP.NET, aunque éstas estén muy alineadas con los eventos impuestos por el pipeline de IIS. Y esto hace virtualmente posible utilizar los módulos OWIN en cualquier tipo de aplicación, siempre que se cumplan los requisitos mínimos impuestos por Katana y los middlewares que utilicemos.
Publicado en Variable not found.
Sin embargo, cuando sabemos que nuestra aplicación va a correr sobre un host ASP.NET/IIS, utilizando el adaptador disponible en el paquete
Microsoft.Owin.Host.SystemWeb
, podemos insertarlos en puntos determinados del pipeline de ejecución de IIS (la famosa “canalización integrada”) para conseguir una mejor integración con frameworks y aplicaciones existentes que a priori no entienden de OWIN (p.e., una aplicación MVC 4 o WebForms).En este post vamos a ver cómo funciona este mecanismo pero, primero, permitid que recuerde a los que acabáis de llegar los posts anteriores de la serie:
- OWIN (I): Introducción fue un primer acercamiento a la conceptual especificación OWIN, sus objetivos y componentes.
- En OWIN (II)- Katana, cinturón blanco vimos qué era Katana, sus principales piezas, y su funcionamiento a alto nivel.
- Seguidamente, en OWIN y Katana (III)- Primeros combates creamos ya nuestras primeras aplicaciones basadas en Katana, una en entorno web y otra usando self-hosting sobre una aplicación de consola.
- OWIN y Katana (IV): Startup y Configuration sirvió para mostrar el proceso de arranque de las aplicaciones OWIN y dónde podemos implementar su código de inicialización.
- Por último, en Owin y Katana (V): Map() y Run() veíamos distintas fórmulas para añadir módulos middleware al pipeline.
En el principio era el módulo HTTP
Un middleware OWIN no difiere mucho, al menos en concepto, de lo que tradicionalmente hemos llamado módulos (Http modules) en ASP.NET. En ambos casos se trata de componentes que podemos insertar en la cadena de acciones que se ejecutan cuando se procesa una petición para introducir lógica personalizada.La diferencia es que los primeros actúan sobre el pipeline de OWIN y los segundos sobre el pipeline de IIS. En este último caso, la lógica de proceso de los módulos se implementa en handlers de los eventos que representan los principales estados por los que pasa una petición:
AcquireRequestState
, AuthenticateRequest
, AuthorizeRequest
, etc. Normalmente para crear un módulo lo que hacíamos era suscribirnos a los eventos en los que queríamos tomar el control:public class MyModule: IHttpModule { public void Init(HttpApplication context) { context.BeginRequest += context_BeginRequest; context.AuthorizeRequest += context_AuthorizeRequest; context.AuthenticateRequest += context_AuthenticateRequest; ... } ... }Estos eventos forman parte del pipeline de ejecución de IIS, siguen un orden predefinido y, por supuesto, están presentes en la ejecución de todas las aplicaciones que corren sobre este servidor. Por esta razón, el adaptador OWIN para IIS/ASP.NET permite entrar en ese juego e insertar los middlewares atendiendo también al orden en que se producen dichos eventos.
La orden de la Katana
La inclusión del paqueteMicrosoft.Owin.Host.SystemWeb
hace que tengamos disponible en el espacio de nombres Owin
el extensor UseStageMarker()
, que permite indicar en qué fase de ejecución del pipeline de IIS queremos introducir los módulos middleware que hemos indicado previamente. Es decir, son marcadores que ponemos en el código para indicar algo como “todos los middlewares introducidos hasta aquí van a ejecutarse en el estado X del pipeline de IIS”. En siguiente ejemplo añadiríamos los middlewares
Foo
y Bar
a la fase de autenticación del proceso, y Baz
a la de autorización:app.Use<Foo>(); app.Use<Bar>(); app.UseStageMarker(PipelineStage.Authenticate); app.Use<Baz>(); app.UseStageMarker(PipelineStage.Authenticate);Como se puede intuir,
UseStageMarker()
recibe como argumento un valor de la enumeración PipelineStage
que refleja la fase del proceso de la petición de ASP.NET a las que queremos enganchar los módulos middleware. Las opciones disponibles, en orden de ejecución, son:public enum PipelineStage { Authenticate, PostAuthenticate, Authorize, PostAuthorize, ResolveCache, PostResolveCache, MapHandler, PostMapHandler, AcquireState, PostAcquireState, PreHandlerExecute, }Por defecto todos los middlewares se añaden a la fase
PreHandlerExecute
, es decir, al final del proceso y justo antes de ejecutarse el handler que procesa la petición.Un detalle importante es que el orden en que llamamos a
UseStageMarker()
se tiene en cuenta. Si lo usamos varias veces en un código, tiene que ser en el mismo orden en el que ocurren los eventos a los que estamos añadiendo los middlewares. Es decir, no podríamos llamar a este método usando Authorize
y cuatro líneas más abajo llamarlo para la fase Authenticate
, que es previa a la primera; en este caso, se vincularían todos los módulos afectados a la fase más temprana de las usadas, que en este caso es Authenticate
.¿Un ejemplo?
Pues sí, mejor vamos a ilustrar todo esto con un ejemplo. Crearemos un módulo HTTP que enviará un mensaje al cliente en la faseMapHandler
y veremos cómo podemos configurar nuestros módulos OWIN para que se ejecuten antes y después de éste.El módulo HTTP es el siguiente:
public class MyModule: IHttpModule { public void Init(HttpApplication context) { context.MapRequestHandler += context_MapRequestHandler; } public void Dispose() { } void context_MapRequestHandler(object sender, EventArgs e) { HttpContext.Current.Response.Write( "<p>Hi from the module (MapRequestHandler event)</p>"); } }Y lo insertamos en el pipeline desde el web.config:
<system.webServer> <modules> <add name="MyModule" type="DemoApp.MyModule"/> </modules> </system.webServer>Por otra parte, tenemos el siguiente módulo middleware:
public class MyMiddleware : OwinMiddleware { private readonly string _text; public MyMiddleware(OwinMiddleware next, string text) : base(next) { _text = text; } public async override Task Invoke(IOwinContext context) { context.Response.Write("<p>"+ _text + " begin</p>"); await Next.Invoke(context); context.Response.Write("<p>"+ _text + " end</p>"); } }Y añadimos varias instancias al pipeline OWIN en la clase
Startup
, así como un módulo final que envía un mensaje al cliente:public class Startup { public void Configuration(IAppBuilder app) { app.Use<MyMiddleware>("One"); app.Use<MyMiddleware>("Two"); app.Use<MyMiddleware>("Three"); app.Use<MyMiddleware>("Four"); app.Run(context => context.Response.WriteAsync("<p><strong>Hello world!!</strong></p>") ); } }Si ejecutamos esta aplicación, obtendremos en el navegador lo siguiente:
Observad que primero se ha ejecutado el módulo HTTP porque los middlewares están asociados por defecto a una fase posterior del proceso del pipeline. A partir de ahí, se van ejecutando sucesivamente en sentido ascendente hasta llegar al módulo final, que retorna el valor y continúa la ejecución de los módulos, ahora en orden inverso.
Utilizamos ahora
UseStageMarker()
para modificar el momento de ejecución de los módulos y vemos seguidamente el resultado:app.Use<MyMiddleware>("One"); app.Use<MyMiddleware>("Two"); app.UseStageMarker(PipelineStage.Authorize); app.Use<MyMiddleware>("Three"); app.Use<MyMiddleware>("Four"); app.UseStageMarker(PipelineStage.PostMapHandler);
Como se observa, a primera llamada a
UseStageMarker()
ha desplazado los dos primeros middlewares a un estado previo al capturado desde el módulo HTTP, y los dos siguientes a uno posterior, por lo que el orden de ejecución ha variado.En definitiva, lo interesante de todo esto es que podemos utilizar componentes middleware en aplicaciones ASP.NET, aunque éstas estén muy alineadas con los eventos impuestos por el pipeline de IIS. Y esto hace virtualmente posible utilizar los módulos OWIN en cualquier tipo de aplicación, siempre que se cumplan los requisitos mínimos impuestos por Katana y los middlewares que utilicemos.
Publicado en Variable not found.
Publicado por José M. Aguilar a las 9:15 a. m.
Etiquetas: katana, owin, tutorial, tutorial-owin-katana
2 Comentarios:
Hola Jm
Gracias por tu aporte a nuestro conocimiento.
Ya se que esta libertad de owin y katana nos va a permitir maravillas pero hoy dia esta refinado lo suficiente para ser usado en produccion. Me preocupa el performance. Si puedes comentarme al respecto seria grandioso.
Saludos
Hola, Reynier.
En principio se trata de un producto estable y listo para producción, aunque obviamente no tenga la misma madurez que otros que llevan ya varias versiones a sus espaldas. Fíjate que las nuevas versiones de WebAPI o SignalR ya están totalmente apoyados en Katana, y esto demuestra la apuesta de Microsoft por estas tecnologías.
En cuanto al rendimiento, en pura teoría debería ser superior a la alternativa ASP.NET tradicional, aunque aún tendremos que esperar un poco para poder quitarnos esta pesada mochila de encima (mira este post: http://weblog.west-wind.com/posts/2013/Nov/23/Checking-out-the-Helios-IIS-Owin-Web-Server-Host).
Saludos.
Enviar un nuevo comentario