意外と知られてない気がするOwin+ASP.NET(IIS) のパイプラインの実行順序

OwinのUseStageMarkerが何を行ってるのか、コードを追いかけても全然わからなかったので、実行順序をキャプチャして、やっと理解することができたので紹介します。
※今回の検証はWebAPIでやりました。

#準備
```Global.axax.cs
//以下を追加
protected void Application_BeginRequest(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_BeginRequest event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_AuthenticateRequest event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_AuthorizeRequest event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_ResolveRequestCache(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_ResolveRequestCache event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Session_Start(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Session_Start event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_AcquireRequestState(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_AcquireRequestState event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_PreRequestHandlerExecute event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_PreRequestHandlerExecute event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_ReleaseRequestState(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_ReleaseRequestState event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_UpdateRequestCache(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_UpdateRequestCache event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}


protected void Application_EndRequest(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_EndRequest event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_PreSendRequestHandlers(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_PreSendRequestHandlers event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}

protected void Application_PreSendRequestContent(object sender, EventArgs e)
{
    Trace.WriteLine("HttpApplication Application_PreSendRequestContent event, Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}
```

```Startup.cs
//以下のように編集
public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "First!");
            return next.Invoke();
        });

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "Authenticate");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.Authenticate);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "PostAuthenticate");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.PostAuthenticate);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "Authorize");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.Authorize);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "PostAuthorize");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.PostAuthorize);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "ResolveCache");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.ResolveCache);


        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "PostResolveCache");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.PostResolveCache);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "MapHandler");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.MapHandler);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "PostMapHandler");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.PostMapHandler);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "AcquireState");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.AcquireState);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "PostAcquireState");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.PostAcquireState);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "PreHandlerExecute");
            return next.Invoke();
        });
        //app.UseStageMarker(PipelineStage.PreHandlerExecute);

        app.Use((context, next) =>
        {
            PrintCurrentIntegratedPipelineStage(context, "2nd Use");
            return next.Invoke();
        });

        app.Run(context =>
        {
            PrintCurrentIntegratedPipelineStage(context, "Content Reposnse");
            return context.Response.WriteAsync("Hello world");
        });
    }

    private void PrintCurrentIntegratedPipelineStage(IOwinContext context, string msg)
    {
        var currentIntegratedpipelineStage = HttpContext.Current.CurrentNotification;
        var trace = context.Get<TextWriter>("host.TraceOutput");

        trace.WriteLine("OWIN event: " + currentIntegratedpipelineStage + " Msg: " + msg + ",Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
    }
}
```

```MyModule1.cs
//新規で作る
public class MyModule1 : IHttpModule
{
    private string _moduleName;

    public void Init(HttpApplication context)
    {
        var nameProp = context.GetType().GetProperty("CurrentModuleCollectionKey", BindingFlags.NonPublic | BindingFlags.Instance);
        _moduleName = (string)nameProp.GetValue(context, null);

        context.BeginRequest += (sender, args) => PrintCurrentIntegratedPipelineStage("BeginRequest");
        context.AuthenticateRequest += (sender, args) => PrintCurrentIntegratedPipelineStage("AuthenticateRequest");
        context.AuthorizeRequest += (sender, args) => PrintCurrentIntegratedPipelineStage("AuthorizeRequest");
        context.ResolveRequestCache += (sender, args) => PrintCurrentIntegratedPipelineStage("ResolveRequestCache");
        context.AcquireRequestState += (sender, args) => PrintCurrentIntegratedPipelineStage("AcquireRequestState");
        context.PreRequestHandlerExecute += (sender, args) => PrintCurrentIntegratedPipelineStage("PreRequestHandlerExecute");
        context.PostRequestHandlerExecute += (sender, args) => PrintCurrentIntegratedPipelineStage("PostRequestHandlerExecute");
        context.ReleaseRequestState += (sender, args) => PrintCurrentIntegratedPipelineStage("ReleaseRequestState");
        context.UpdateRequestCache += (sender, args) => PrintCurrentIntegratedPipelineStage("UpdateRequestCache");
        context.EndRequest += (sender, args) => PrintCurrentIntegratedPipelineStage("EndRequest");
    }

    private void PrintCurrentIntegratedPipelineStage(string msg)
    {
        var currentIntegratedpipelineStage = HttpContext.Current.CurrentNotification;

        Trace.WriteLine(_moduleName + "1 IIS event: " + currentIntegratedpipelineStage + " Msg: " + msg + ",Thread:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
    }

    public void Dispose()
    {
    }
}
```

```Web.config
<system.webServer>
　<!-- 追加 -->
  <modules>
    <add name="HttpModule1" type="WebApplication1.MyModule1"/>
    <add name="HttpModule2" type="WebApplication1.MyModule1"/>
    <add name="HttpModule3" type="WebApplication1.MyModule1"/>
  </modules>
</system.webServer>
```

#検証
※初回リクエスト時は内容変わるので２回目のリクエストをキャプチャしています。

```実行結果.
HttpModule11 IIS event: BeginRequest Msg: BeginRequest,Thread:6
HttpModule21 IIS event: BeginRequest Msg: BeginRequest,Thread:6
HttpModule31 IIS event: BeginRequest Msg: BeginRequest,Thread:6
HttpApplication Application_BeginRequest event, Thread:6
HttpModule11 IIS event: AuthenticateRequest Msg: AuthenticateRequest,Thread:6
HttpModule21 IIS event: AuthenticateRequest Msg: AuthenticateRequest,Thread:6
HttpModule31 IIS event: AuthenticateRequest Msg: AuthenticateRequest,Thread:6
HttpApplication Application_AuthenticateRequest event, Thread:6
HttpModule11 IIS event: AuthorizeRequest Msg: AuthorizeRequest,Thread:6
HttpModule21 IIS event: AuthorizeRequest Msg: AuthorizeRequest,Thread:6
HttpModule31 IIS event: AuthorizeRequest Msg: AuthorizeRequest,Thread:6
HttpApplication Application_AuthorizeRequest event, Thread:6
HttpModule11 IIS event: ResolveRequestCache Msg: ResolveRequestCache,Thread:6
HttpModule21 IIS event: ResolveRequestCache Msg: ResolveRequestCache,Thread:6
HttpModule31 IIS event: ResolveRequestCache Msg: ResolveRequestCache,Thread:6
HttpApplication Application_ResolveRequestCache event, Thread:6
HttpModule11 IIS event: AcquireRequestState Msg: AcquireRequestState,Thread:6
HttpModule21 IIS event: AcquireRequestState Msg: AcquireRequestState,Thread:6
HttpModule31 IIS event: AcquireRequestState Msg: AcquireRequestState,Thread:6
HttpApplication Application_AcquireRequestState event, Thread:6
HttpModule11 IIS event: PreExecuteRequestHandler Msg: PreRequestHandlerExecute,Thread:6
HttpModule21 IIS event: PreExecuteRequestHandler Msg: PreRequestHandlerExecute,Thread:6
HttpModule31 IIS event: PreExecuteRequestHandler Msg: PreRequestHandlerExecute,Thread:6
OWIN event: PreExecuteRequestHandler Msg: First!,Thread:6
OWIN event: PreExecuteRequestHandler Msg: Authenticate,Thread:6
OWIN event: PreExecuteRequestHandler Msg: PostAuthenticate,Thread:6
OWIN event: PreExecuteRequestHandler Msg: Authorize,Thread:6
OWIN event: PreExecuteRequestHandler Msg: PostAuthorize,Thread:6
OWIN event: PreExecuteRequestHandler Msg: ResolveCache,Thread:6
OWIN event: PreExecuteRequestHandler Msg: PostResolveCache,Thread:6
OWIN event: PreExecuteRequestHandler Msg: MapHandler,Thread:6
OWIN event: PreExecuteRequestHandler Msg: PostMapHandler,Thread:6
OWIN event: PreExecuteRequestHandler Msg: AcquireState,Thread:6
OWIN event: PreExecuteRequestHandler Msg: PostAcquireState,Thread:6
OWIN event: PreExecuteRequestHandler Msg: PreHandlerExecute,Thread:6
OWIN event: PreExecuteRequestHandler Msg: 2nd Use,Thread:6
OWIN event: PreExecuteRequestHandler Msg: Content Reposnse,Thread:6
HttpModule11 IIS event: EndRequest Msg: EndRequest,Thread:7
HttpModule21 IIS event: EndRequest Msg: EndRequest,Thread:7
HttpModule31 IIS event: EndRequest Msg: EndRequest,Thread:7
HttpApplication Application_EndRequest event, Thread:7
HttpApplication Application_PreSendRequestContent event, Thread:7
```

ここで、Startup.csのコメントアウト(app.UseStageMarker)を外してもう一度実行すると

```実行結果.
HttpModule11 IIS event: BeginRequest Msg: BeginRequest,Thread:7
HttpModule21 IIS event: BeginRequest Msg: BeginRequest,Thread:7
HttpModule31 IIS event: BeginRequest Msg: BeginRequest,Thread:7
HttpApplication Application_BeginRequest event, Thread:7
HttpModule11 IIS event: AuthenticateRequest Msg: AuthenticateRequest,Thread:7
HttpModule21 IIS event: AuthenticateRequest Msg: AuthenticateRequest,Thread:7
HttpModule31 IIS event: AuthenticateRequest Msg: AuthenticateRequest,Thread:7
OWIN event: AuthenticateRequest Msg: First!,Thread:7
OWIN event: AuthenticateRequest Msg: Authenticate,Thread:7
HttpApplication Application_AuthenticateRequest event, Thread:7
OWIN event: AuthenticateRequest Msg: PostAuthenticate,Thread:7
HttpModule11 IIS event: AuthorizeRequest Msg: AuthorizeRequest,Thread:7
HttpModule21 IIS event: AuthorizeRequest Msg: AuthorizeRequest,Thread:7
HttpModule31 IIS event: AuthorizeRequest Msg: AuthorizeRequest,Thread:7
OWIN event: AuthorizeRequest Msg: Authorize,Thread:7
HttpApplication Application_AuthorizeRequest event, Thread:7
OWIN event: AuthorizeRequest Msg: PostAuthorize,Thread:7
HttpModule11 IIS event: ResolveRequestCache Msg: ResolveRequestCache,Thread:7
HttpModule21 IIS event: ResolveRequestCache Msg: ResolveRequestCache,Thread:7
HttpModule31 IIS event: ResolveRequestCache Msg: ResolveRequestCache,Thread:7
OWIN event: ResolveRequestCache Msg: ResolveCache,Thread:7
HttpApplication Application_ResolveRequestCache event, Thread:7
OWIN event: ResolveRequestCache Msg: PostResolveCache,Thread:7
OWIN event: MapRequestHandler Msg: MapHandler,Thread:7
OWIN event: MapRequestHandler Msg: PostMapHandler,Thread:7
HttpModule11 IIS event: AcquireRequestState Msg: AcquireRequestState,Thread:7
HttpModule21 IIS event: AcquireRequestState Msg: AcquireRequestState,Thread:7
HttpModule31 IIS event: AcquireRequestState Msg: AcquireRequestState,Thread:7
OWIN event: AcquireRequestState Msg: AcquireState,Thread:7
HttpApplication Application_AcquireRequestState event, Thread:7
OWIN event: AcquireRequestState Msg: PostAcquireState,Thread:7
HttpModule11 IIS event: PreExecuteRequestHandler Msg: PreRequestHandlerExecute,Thread:7
HttpModule21 IIS event: PreExecuteRequestHandler Msg: PreRequestHandlerExecute,Thread:7
HttpModule31 IIS event: PreExecuteRequestHandler Msg: PreRequestHandlerExecute,Thread:7
OWIN event: PreExecuteRequestHandler Msg: PreHandlerExecute,Thread:7
OWIN event: PreExecuteRequestHandler Msg: 2nd Use,Thread:7
OWIN event: PreExecuteRequestHandler Msg: Content Reposnse,Thread:7
HttpModule11 IIS event: EndRequest Msg: EndRequest,Thread:25
HttpModule21 IIS event: EndRequest Msg: EndRequest,Thread:25
HttpModule31 IIS event: EndRequest Msg: EndRequest,Thread:25
HttpApplication Application_EndRequest event, Thread:25
HttpApplication Application_PreSendRequestContent event, Thread:25
```

#まとめ
・Owinの場合、PreExecuteRequestHandlerとEndRequestの間に割り込み、ここでパイプラインを構築することができる。
・ここで、UseStageMarkerによって割り込みタイミングを(ある程度)コントロールできる。
・UserStageMakerを使うと、HttpModuleとHttpApplicationの間に割り込む。

###[参考](http://takepara.tumblr.com/post/66858451933/owin-middleware-in-the-iis-integrated-pipeline)