Middleware de OWIN en la canalización integrada de IIS

por Praburaj Thiagarajan, Rick Anderson

En este artículo se muestra cómo ejecutar componentes de middleware OWIN (OMCs) en la canalización integrada de IIS y cómo establecer el evento de canalización en el que se ejecuta un OMC. Antes de leer este tutorial, debe revisar una introducción a la detección de la clase de inicio de Project Katana y OWIN . Este tutorial fue escrito por Rick Anderson ( @RickAndMSFT ), Chris Ross, Praburaj Thiagarajan y Howard Dierking ( @howard_Dierking ).

Aunque los componentes de middleware OWIN (OMCs) están diseñados principalmente para ejecutarse en una canalización independiente del servidor, es posible ejecutar un OMC también en la canalización integrada de IIS ( no se admite el modo clásico). Se puede realizar una OMC para trabajar en la canalización integrada de IIS mediante la instalación del paquete siguiente desde la consola del administrador de paquetes (PMC):

Install-Package Microsoft.Owin.Host.SystemWeb

Esto significa que todos los marcos de aplicaciones, incluso aquellos que todavía no se pueden ejecutar fuera de IIS y System. Web, pueden beneficiarse de los componentes de middleware OWIN existentes.

Note

Todos los paquetes de Microsoft.Owin.Security.* que se envían con el nuevo sistema de identidad en Visual Studio 2013 (por ejemplo: cookies, cuenta de Microsoft, Google, Facebook, Twitter, token de portador, OAuth, servidor de autorización, JWT, Azure Active Directory y servicios de Federación de Active Directory) se crean como OMCs y se pueden usar en escenarios autohospedados y hospedados en IIS.

Cómo se ejecuta el middleware OWIN en la canalización integrada de IIS

En el caso de las aplicaciones de consola OWIN, la canalización de la aplicación compilada con la configuración de inicio se establece mediante el orden en que se agregan los componentes mediante el método IAppBuilder.Use. Es decir, la canalización OWIN en el tiempo de ejecución de Katana procesará OMCs en el orden en el que se registraron mediante IAppBuilder.Use. En la canalización integrada de IIS, la canalización de solicitudes consta de httpModules suscrito a un conjunto predefinido de eventos de canalización como BeginRequest, AuthenticateRequest, AuthorizeRequest, etc.

Si comparamos un OMC con el de un HttpModule en el mundo de ASP.net, se debe registrar un OMC en el evento de canalización predefinido correcto. Por ejemplo, el MyModule HttpModule se invocará cuando llegue una solicitud a la fase AuthenticateRequest de la canalización:

public class MyModule : IHttpModule
{
    public void Dispose()
    {
        //clean-up code here.
    }
    public void Init(HttpApplication context)
    {
        // An example of how you can handle AuthenticateRequest events.
        context.AuthenticateRequest += ctx_AuthRequest;
    }
    void ctx_AuthRequest(object sender, EventArgs e)
    {
        // Handle event.
    }
}

Para que un OMC participe en este mismo orden de ejecución basado en eventos, el código en tiempo de ejecución de Katana examina la configuración de inicio y suscribe cada uno de los componentes de middleware a un evento de canalización integrada. Por ejemplo, el siguiente código de registro y OMC le permite ver el registro de eventos predeterminado de los componentes de middleware. (Para obtener instrucciones más detalladas sobre cómo crear una clase de inicio de OWIN, vea detección de clases de inicio de Owin).

  1. Cree un proyecto de aplicación Web vacío y asígnele el nombre owin2.

  2. En la consola del administrador de paquetes (PMC), ejecute el siguiente comando:

    Install-Package Microsoft.Owin.Host.SystemWeb
    
  3. Agregue un OWIN Startup Class y asígnele el nombre Startup. Reemplace el código generado por lo siguiente (se resaltan los cambios):

    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;
    using System.Web;
    using System.IO;
    using Microsoft.Owin.Extensions;
    [assembly: OwinStartup(typeof(owin2.Startup))]
    namespace owin2
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                app.Use((context, next) =>
                {
                    PrintCurrentIntegratedPipelineStage(context, "Middleware 1");
                    return next.Invoke();
                });
                app.Use((context, next) =>
                {
                    PrintCurrentIntegratedPipelineStage(context, "2nd MW");
                    return next.Invoke();
                }); 
                app.Run(context =>
                {
                    PrintCurrentIntegratedPipelineStage(context, "3rd MW");
                    return context.Response.WriteAsync("Hello world");
                });            
            }
            private void PrintCurrentIntegratedPipelineStage(IOwinContext context, string msg)
            {
                var currentIntegratedpipelineStage = HttpContext.Current.CurrentNotification;
                context.Get<TextWriter>("host.TraceOutput").WriteLine(
                    "Current IIS event: " + currentIntegratedpipelineStage
                    + " Msg: " + msg);
            }
        }
    }
    
  4. Presione F5 para ejecutar la aplicación.

La configuración de inicio configura una canalización con tres componentes de middleware, los dos primeros muestran información de diagnóstico y el último que responde a los eventos (y también muestra información de diagnóstico). El método PrintCurrentIntegratedPipelineStage muestra el evento de canalización integrada en el que se invoca a este middleware y un mensaje. Las ventanas de salida muestran lo siguiente:

Current IIS event: PreExecuteRequestHandler Msg: Middleware 1
Current IIS event: PreExecuteRequestHandler Msg: 2nd MW
Current IIS event: PreExecuteRequestHandler Msg: 3rd MW

El tiempo de ejecución de Katana asignó cada uno de los componentes de middleware OWIN a PreExecuteRequestHandler de forma predeterminada, que corresponde al evento de canalización de IIS PreRequestHandlerExecute.

Marcadores de fase

Puede marcar OMCs para que se ejecute en fases específicas de la canalización mediante el método de extensión IAppBuilder UseStageMarker(). Para ejecutar un conjunto de componentes de middleware durante una fase determinada, inserte un marcador de fase justo después de que el último componente sea el establecido durante el registro. Hay reglas en qué fase de la canalización se puede ejecutar el software intermedio y se deben ejecutar los componentes de pedido (las reglas se explican más adelante en el tutorial). Agregue el método UseStageMarker al código de Configuration como se muestra a continuación:

public void Configuration(IAppBuilder app)
{
    app.Use((context, next) =>
    {
        PrintCurrentIntegratedPipelineStage(context, "Middleware 1");
        return next.Invoke();
    });
    app.Use((context, next) =>
    {
        PrintCurrentIntegratedPipelineStage(context, "2nd MW");
        return next.Invoke();
    });
    app.UseStageMarker(PipelineStage.Authenticate);
    app.Run(context =>
    {
        PrintCurrentIntegratedPipelineStage(context, "3rd MW");
        return context.Response.WriteAsync("Hello world");
    });
    app.UseStageMarker(PipelineStage.ResolveCache);
}

La llamada app.UseStageMarker(PipelineStage.Authenticate) configura todos los componentes de middleware previamente registrados (en este caso, nuestros dos componentes de diagnóstico) para que se ejecuten en la fase de autenticación de la canalización. El último componente middleware (que muestra diagnósticos y responde a las solicitudes) se ejecutará en la ResolveCache fase (el evento ResolveRequestCache ).

Presione F5 para ejecutar la aplicación. La ventana salida muestra lo siguiente:

Current IIS event: AuthenticateRequest Msg: Middleware 1
Current IIS event: AuthenticateRequest Msg: 2nd MW
Current IIS event: ResolveRequestCache Msg: 3rd MW

Reglas de marcador de fase

Los componentes de middleware Owin (OMC) se pueden configurar para que se ejecuten en los siguientes eventos de fase de canalización OWIN:

public enum PipelineStage
{
    Authenticate = 0,
    PostAuthenticate = 1,
    Authorize = 2,
    PostAuthorize = 3,
    ResolveCache = 4,
    PostResolveCache = 5,
    MapHandler = 6,
    PostMapHandler = 7,
    AcquireState = 8,
    PostAcquireState = 9,
    PreHandlerExecute = 10,
}
  1. De forma predeterminada, OMCs se ejecuta en el último evento (PreHandlerExecute). Este es el motivo por el que el primer código de ejemplo muestra "PreExecuteRequestHandler".

  2. Puede usar el método a app.UseStageMarker para registrar un OMC para que se ejecute antes, en cualquier fase de la canalización OWIN indicada en la enumeración PipelineStage.

  3. La canalización OWIN y la canalización IIS están ordenadas, por lo que las llamadas a app.UseStageMarker deben estar en orden. No se puede establecer el controlador de eventos en un evento que precede al último evento registrado en para app.UseStageMarker. Por ejemplo, después de llamar a:

    app.UseStageMarker(PipelineStage.Authorize);
    

    no se atenderán las llamadas a app.UseStageMarker que pasen Authenticate o PostAuthenticate, y no se producirá ninguna excepción. OMCs se ejecuta en la fase más reciente, que de forma predeterminada es PreHandlerExecute. Los marcadores de fase se usan para que se ejecuten antes. Si especifica marcadores de fase fuera de orden, se redondea al marcador anterior. En otras palabras, la adición de un marcador de fase indica "ejecución no posterior a la fase X". OMC se ejecuta en el marcador de fase más antiguo que se agregó después de ellos en la canalización OWIN.

  4. La primera fase de llamadas a app.UseStageMarker WINS. Por ejemplo, si cambia el orden de las llamadas app.UseStageMarker del ejemplo anterior:

    public void Configuration(IAppBuilder app)
    {
        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "Middleware 1");
            return next.Invoke();
        });
        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "2nd MW");
            return next.Invoke();
        });
        app.UseStageMarker(PipelineStage.ResolveCache);
        app.Run(context =>
        {
            PrintCurrentIntegratedPipelineStage(context, "3rd MW");
            return context.Response.WriteAsync("Hello world");
        });
        app.UseStageMarker(PipelineStage.Authenticate);
    }
    

    Se mostrará la ventana de salida:

    Current IIS event: AuthenticateRequest Msg: Middleware 1
    Current IIS event: AuthenticateRequest Msg: 2nd MW
    Current IIS event: AuthenticateRequest Msg: 3rd MW
    

    El OMCs se ejecuta en la fase AuthenticateRequest, porque el último OMC registrado con el evento Authenticate y el evento Authenticate precede a todos los demás eventos.