Middleware OWIN en la canalización integrada de IIS

Por Praburaj Thiagarajan y Rick Anderson

En este artículo, se muestra cómo ejecutar componentes de middleware OWIN (OMC) en la canalización integrada de IIS y cómo establecer el evento de canalización en el que se ejecuta un OMC. Debe revisar Introducción al proyecto Katana y Detección de clases de inicio de OWIN antes de leer este tutorial. Este tutorial fue escrito por Rick Anderson (@RickAndMSFT), Chris Ross, Praburaj Thiagarajan y Howard Dierking (@howard_dierking).

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

Install-Package Microsoft.Owin.Host.SystemWeb

Esto significa que todos los marcos de trabajo de la aplicación, incluso aquellos que aún no se pueden ejecutar fuera de IIS y System.Web, pueden beneficiarse de los componentes de middleware OWIN existentes.

Nota:

Todos los paquetes Microsoft.Owin.Security.* se proporcionan con el nuevo sistema de identidades de 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 OMC 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 creada con la configuración de inicio se establece mediante el orden en que se agregan los componentes con el método IAppBuilder.Use. Es decir, la canalización OWIN en el entorno de ejecución de Katana procesa los OMC en el orden en el que se registraron con IAppBuilder.Use. En la canalización integrada de IIS, la canalización de solicitud consta de un elemento HttpModules suscrito a un conjunto predefinido de eventos de canalización, como BeginRequest, AuthenticateRequest, AuthorizeRequest, etc. Observe que el paquete Nuget Microsoft.Owin.Host.SystemWeb registra el elemento OwinHttpModule. Normalmente, HttpModule se registra en IIS mediante el archivo Web.config, pero Microsoft.Owin.Host.SystemWeb usa una característica de IIS llamada PreApplicationStartMethodAttribute y HttpApplication.RegisterModule(Type) para registrar dinámicamente el elemento OwinHttpModule en la canalización en IIS.

Si comparamos un OMC con el de un HttpModule en el mundo ASP.NET, un OMC se debe registrar en el evento de canalización predefinido correcto. Por ejemplo, el elemento HttpModule MyModule se invocará cuando una solicitud llegue 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 del entorno 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 integrado. Por ejemplo, el siguiente código de registro y OMC le permiten 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, consulte Detección de clases de inicio de OWIN).

  1. Cree un proyecto de aplicación web vacío con el nombre owin2.

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

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

    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. Pulse 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 responde a los eventos (y también muestra información de diagnóstico). El método PrintCurrentIntegratedPipelineStage muestra el evento de canalización integrado en el que se invoca a este middleware y un mensaje. La ventana de salida muestra lo siguiente:

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

El entorno de ejecución de Katana ha asignado cada uno de los componentes de middleware OWIN a PreExecuteRequestHandler de manera predeterminada, que corresponde al evento PreRequestHandlerExecute de la canalización de IIS.

Marcadores de fase

Puede marcar los OMC para que se ejecuten 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 se establezca el último componente durante el registro. Hay reglas sobre la fase de la canalización en la que se puede ejecutar middleware y sobre el orden en el que deben ejecutarse los componentes (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 a app.UseStageMarker(PipelineStage.Authenticate) configura todos los componentes de middleware registrados anteriormente (en este caso, nuestros dos componentes de diagnóstico) para ejecutarse en la fase de autenticación de la canalización. El último componente de middleware (que muestra los diagnósticos y responde a las solicitudes) se ejecutará en la fase ResolveCache (el evento ResolveRequestCache).

Pulse F5 para ejecutar la aplicación. La ventana de 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 marcadores de fase

Los componentes de middleware Owin (OMC) se pueden configurar para ejecutarse en los siguientes eventos de fase de canalización de 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 manera predeterminada, los OMC se ejecutan en el último evento (PreHandlerExecute). Por eso nuestro primer código de ejemplo muestra "PreExecuteRequestHandler".

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

  3. La canalización de OWIN y la canalización de 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 con app.UseStageMarker. Por ejemplo, después de llamar a:

    app.UseStageMarker(PipelineStage.Authorize);
    

    las llamadas a app.UseStageMarker que pasan Authenticate o PostAuthenticate no se respetarán y no se producirá ninguna excepción. Los OMC se ejecutan en la fase más reciente, que de manera predeterminada es PreHandlerExecute. Los marcadores de fase se usan para que se ejecuten anteriormente. Si especifica marcadores de fase desordenados, redondeamos al marcador anterior. En otras palabras, agregar un marcador de fase indica "Ejecutar no después de la fase X". Los OMC se ejecutan en el primer marcador de fase agregado después de ellos en la canalización de OWIN.

  4. Gana la primera fase de las llamadas a app.UseStageMarker. Por ejemplo, si cambia el orden de las llamadas a app.UseStageMarker de nuestro 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);
    }
    

    La ventana de salida mostrará lo siguiente:

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

    Todos los OMC se ejecutan en la fase AuthenticateRequest, ya que el último OMC se registró con el evento Authenticate y el evento Authenticate precede a todos los demás eventos.