IIS 統合パイプラインの OWIN ミドルウェア

作成者: Praburaj ThiagarajanRick Anderson

この記事では、IIS 統合パイプラインで OWIN ミドルウェア コンポーネント (OMC) を実行する方法と、OMC が実行するパイプライン イベントを設定する方法について説明します。 このチュートリアルを読む前に、「 Project KatanaOWIN スタートアップ クラス検出 の概要」を確認する必要があります。 このチュートリアルは、Rick Anderson ( @RickAndMSFT )、Chris Ross、Praburaj Thiagarajan、および Howard Dierking ( @howard_dierking ) によって記述されました。

OWIN ミドルウェア コンポーネント (OMC) は主にサーバーに依存しないパイプラインで実行するように設計されていますが、IIS 統合パイプラインでも OMC を実行できます (クラシック モードはサポートされていません)。 OMC を IIS 統合パイプラインで動作させるには、パッケージ マネージャー コンソール (PMC) から次のパッケージをインストールします。

Install-Package Microsoft.Owin.Host.SystemWeb

つまり、IIS や System.Web の外部でまだ実行できないアプリケーション フレームワークであっても、すべてのアプリケーション フレームワークは、既存の OWIN ミドルウェア コンポーネントの恩恵を受けることができます。

Note

Microsoft.Owin.Security.* Visual Studio 2013の新しい ID システムに付属するすべてのパッケージ (Cookie、Microsoft アカウント、Google、Facebook、Twitter、ベアラー トークン、OAuth、承認サーバー、JWT、Azure Active Directory、Active Directory フェデレーション サービスなど) は OMC として作成され、セルフホステッドと IIS ホストの両方のシナリオで使用できます。

IIS 統合パイプラインで OWIN ミドルウェアを実行する方法

OWIN コンソール アプリケーションの場合、 スタートアップ構成 を使用してビルドされたアプリケーション パイプラインは、 メソッドを使用して IAppBuilder.Use コンポーネントを追加する順序によって設定されます。 つまり、 Katana ランタイムの OWIN パイプラインは、 を使用して IAppBuilder.Use登録された順序で OMC を処理します。 IIS 統合パイプラインでは、要求パイプラインは、BeginRequest、AuthenticateRequestAuthorizeRequest などのパイプライン イベントの定義済みのセットにサブスクライブされた HttpModules で構成されます。 Microsoft.Owin.Host.SystemWeb nuget パッケージによって が登録されていることに注意してくださいOwinHttpModule。 通常、 HttpModule は ファイルを介して Web.config IIS に登録されますがMicrosoft.Owin.Host.SystemWeb、 と HttpApplication.RegisterModule(Type) 呼ばれる PreApplicationStartMethodAttribute IIS 機能を使用して、 OwinHttpModule を IIS パイプラインに動的に登録します。

OMC を ASP.NET 世界の HttpModule と比較する場合は、OMC を正しい定義済みパイプライン イベントに登録する必要があります。 たとえば、要求がパイプラインの AuthenticateRequest ステージに来ると、HttpModule MyModule が呼び出されます。

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.
    }
}

OMC がこの同じイベント ベースの実行順序に参加するために、 Katana ランタイム コードは スタートアップ構成 をスキャンし、各ミドルウェア コンポーネントを統合パイプライン イベントにサブスクライブします。 たとえば、次の OMC と登録コードを使用すると、ミドルウェア コンポーネントの既定のイベント登録を確認できます。 (OWIN スタートアップ クラスの作成に関する詳細な手順については、「 OWIN スタートアップ クラスの検出」を参照してください)。

  1. 空の Web アプリケーション プロジェクトを作成し、 owin2 という名前を付けます。

  2. パッケージ マネージャー コンソール (PMC) から、次のコマンドを実行します。

    Install-Package Microsoft.Owin.Host.SystemWeb
    
  3. OWIN Startup Class 追加し、 という名前を付けます Startup。 生成されたコードを次のように置き換えます (変更が強調表示されています)。

    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. F5 キーを押してアプリを実行します。

スタートアップ構成では、3 つのミドルウェア コンポーネントを含むパイプラインを設定します。最初の 2 つは診断情報を表示し、最後の 1 つはイベントに応答します (また、診断情報も表示します)。 メソッドは PrintCurrentIntegratedPipelineStage 、このミドルウェアが呼び出された統合パイプライン イベントとメッセージを表示します。 出力ウィンドウには、次の情報が表示されます。

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

Katana ランタイムは、既定で各 OWIN ミドルウェア コンポーネントを PreExecuteRequestHandler にマップしました。これは、IIS パイプライン イベント PreRequestHandlerExecute に対応します。

ステージ マーカー

拡張メソッドを使用して、パイプラインの特定のステージで実行するように OMC を IAppBuilder UseStageMarker() マークできます。 特定のステージで一連のミドルウェア コンポーネントを実行するには、登録時に最後のコンポーネントがセットの直後にステージ マーカーを挿入します。 ミドルウェアを実行できるパイプラインのステージと、順序コンポーネントを実行する必要があるルールがあります (規則については、このチュートリアルの後半で説明します)。 次に UseStageMarker 示すように、 メソッドをコードに Configuration 追加します。

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);
}

この呼び出しでは app.UseStageMarker(PipelineStage.Authenticate) 、パイプラインの認証ステージで実行するように、以前に登録されたすべてのミドルウェア コンポーネント (この場合は 2 つの診断コンポーネント) が構成されます。 最後のミドルウェア コンポーネント (診断が表示され、要求に応答します) は、ステージ (ResolveRequestCache イベント) でResolveCache実行されます。

F5 キーを押してアプリを実行します。出力ウィンドウには、次の情報が表示されます。

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

ステージ マーカー ルール

Owin ミドルウェア コンポーネント (OMC) は、次の 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. 既定では、OMC は最後のイベント (PreHandlerExecute) で実行されます。 そのため、最初のコード例では "PreExecuteRequestHandler" が表示されました。

  2. メソッドを app.UseStageMarker 使用して、列挙型に一覧表示されている OWIN パイプラインの任意のステージで、前に実行する OMC を PipelineStage 登録できます。

  3. OWIN パイプラインと IIS パイプラインは順序付けされているため、 の app.UseStageMarker 呼び出しは順番に行う必要があります。 に登録された最後のイベントの前にあるイベントにイベント ハンドラーを app.UseStageMarker設定することはできません。 たとえば、 を呼び出 した後 :

    app.UseStageMarker(PipelineStage.Authorize);
    

    または へのapp.UseStageMarkerAuthenticatePostAuthenticateび出しは受け入れられないので、例外はスローされません。 OMC は最新のステージで実行されます。既定では です PreHandlerExecute。 ステージ マーカーは、前に実行するために使用されます。 ステージ マーカーを順に指定した場合は、前のマーカーに丸め込みます。 つまり、ステージ マーカーを追加すると、"ステージ X より後で実行する" と表示されます。 OMC は、OWIN パイプラインでその後に追加された最も早いステージ マーカーで実行されます。

  4. 優先する app.UseStageMarker 呼び出しの最も早い段階。 たとえば、前の例から呼び出しの app.UseStageMarker 順序を切り替えるとします。

    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);
    }
    

    出力ウィンドウに次の情報が表示されます。

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

    OMC はすべてステージで実行されます。これは、イベントに AuthenticateRequest 登録された Authenticate 最後の OMC と、イベントが Authenticate 他のすべてのイベントの前にあるためです。