首先特別說明下在startup中註冊完中間件的兩個注意事項,看到有人寫的東西有誤導人的做用。關於startup啓動發現類的內容,參照這裏 http://www.asp.net/aspnet/overview/owin-and-katana/owin-startup-class-detectionapp
1. 使用IApplicationBuilder.User註冊中間件是有前後順序關係的。asp.net
2. 註冊的中間件的執行過程是這樣的:輸入初始化是按照順序來的,輸出執行是反順序來的。
請求發生-->初始化中間件1--->初始化中間件n-->app忽略中間件方法,直接響應輸出--------->中間件n Invoke執行處理-->中間件1 Invoke執行處理--->響應輸出async
進入正文ide
OWIN middleware 必須是具備如下代碼特徵,要麼是直接在startup類中直接註冊,要麼就是寫的中間件類中方法返回。ui
Func<IDictionary<string, object>, Task> //這個function具備一個上下文的字典參數(OWIN environment dictionary),並返回Task
這段特徵碼中的IDictionary<string, object>其實已經被katana的server層包裝成字典形式的請求上下文(HttpContext)IOwinContext,能夠使用上下文屬性environment訪問字典值this
咱們會以這種形式註冊中間件spa
IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware); //middleware 能夠是委託 or 類型 or 實例
中間件註冊進入管道,因爲中間件返回一個Task,就能保證管道在處理的時候能找到下一個執行的Task(就是下邊代碼中的next參數,那麼next就是已知的第一個RequestDelegate參數)來處理請求和響應。Task就是返回的具備中間件特徵的中間件。.net
下面咱們看下第一種寫法code
app.Use(new Func<RequestDelegate, RequestDelegate>(next => (async context => { Console.WriteLine("初始化組件開始"); await next.Invoke(context); Console.WriteLine("管道下步執行完畢"); })));
以上代碼中會在請求時在控制檯輸出「初始化組件開始」,當組件的下一個步驟執行完畢後,會再打印出「管道下步執行完畢」。server
有時候組件裏沒啥規則,可是也必須接受next做爲參數,可是能夠忽略它,而且仍然須要返回一個task,因此能夠這樣寫
app.Use(new Func<RequestDelegate, RequestDelegate>(ignoreNext => (content=> { Console.WriteLine("The request ends with me!"); return Task.FromResult(0); })));
第二種寫法是將已有的方法傳遞給委託。若是你有一些邏輯須要抽象出來,但又不想單獨寫一箇中間件類,這個寫法就比較合適
public class Startup { public void Configuration(IAppBuilder app) { app.Use(new Func<RequestDelegate, RequestDelegate>(next => content=> Invoke(next, content))); } private async Task Invoke(RequestDelegate next, IDictionary<string, object> environment) { Console.WriteLine("初始化組件開始"); await next.Invoke(environment); Console.WriteLine("管道下步執行完畢"); } }
若是使用一下代碼註冊組件,那麼久必須寫一個實際的中間件類了
app.Use(typeof(LoggingMiddleware));
或者以中間件實例來註冊
app.Use(new LoggingMiddleware());
第三種寫法是實現一個實際的中間件類
public class LoggingMiddleware { private RequestDelegate next; public LoggingMiddleware(RequestDelegate next) { this.next = next; } public async Task Invoke(IDictionary<string, object> environment) { Console.WriteLine("初始化組件開始"); await next.Invoke(environment); Console.WriteLine("管道執行完畢"); } }
第四種寫法咱們能夠集成Microsoft.Owin庫中的OwinMiddleware基類來實現中間件類。它提供了強類型訪問IOwincontext。
public class LoggingMiddleware : OwinMiddleware { public LoggerMiddleware(OwinMiddleware next) : base(next) { } public async override Task Invoke(IOwinContext context) { Console.WriteLine("初始化組件開始"); await Next.Invoke(context); Console.WriteLine("管道執行完畢"); } }
以上幾種寫法實現都幹了同樣的事情,其實更多複雜的中間件定義能夠參考下Microsoft.AspNet.Diagnostics下的幾種中間件實現方式,比入WelcomePageMiddleware.cs,就是咱們在app中使用UserWelcomPage()方法註冊的中間件。