OWIN系列之自己動手編寫中間件
一、前言
1.基於OWIN的項目擺脫System.Web束縛脫穎而出,輕量級+跨平台,使得ASP.NET應用程序只需依賴這個抽象接口,不用關心所運行的Web服務器。
2.OWIN.dll介紹
使用反編譯工具打開Owin.dll,你會發現類庫中就只有一個IAppBuilder接口,所以說OWIN是針對.NET平台的開放Web接口。
3.Microsoft.Owin.dll
Microsoft.Owin.dll是微軟對Owin的具體實現,其中就包括我們今天的主題"中間件"。下文將使用代碼描述自定義基於Owin的"中間件"。
二、環境准備
1.Visual Studio 2015 Update1
2.tinyfox-2.3.2-common --用作Owin Host
三、項目基架搭建和介紹
1.創建一個空的Web站點,移除除了System的所有引用
2. 使用NuGet命令安裝安裝Microsoft.Owin
PM> Install-Package Microsoft.Owin
3.安裝成功后的引用,可以看到,Owin.dll是依賴項,所以自動下載
圖1 所有引用
4.查看Owin.dll結構和IAppBuilder接口代碼
圖2 Owin.dll結構
圖3 IAppBuilder接口代碼
5.OwinMiddleware介紹
OwinMiddleware 是位於Microsoft.Owin.dll中的一個抽象類,我們會用到OwinMiddleware中的Next,簡單的說就是當前中間件無法匹配請求則會將請求轉向下一個中間件處理,直至成功處理,當然這個取決你的程序中是否有轉向代碼,下文中將詳細介紹。
四、自己動手編寫中間件
1.新建類MyMiddleware繼承OwinMiddleware並且實現Invoke函數,附代碼;在Invoke中根據不同的URL PATH調用不同的處理方法
1 /// <summary> 2 /// OWIN "中間件" - MyMiddleware 3 /// </summary> 4 public class MyMiddleware : OwinMiddleware 5 { 6 7 8 /// <summary> 9 /// 構造函數,第一個參數必須為 OwinMiddleware對象 ;第一個參數是固定的,后邊還可以添加自定義的其它參數 10 /// </summary> 11 /// <param name="next">下一個中間件</param> 12 public MyMiddleware(OwinMiddleware next) 13 : base(next) 14 { 15 16 } 17 18 19 /// <summary> 20 /// 處理用戶請求的具體方法,該方法是必須的 21 /// </summary> 22 /// <param name="c">OwinContext對象</param> 23 /// <returns></returns> 24 public override Task Invoke(IOwinContext c) 25 { 26 if (Next != null && c.Request.Path.Value != "/home/index") 27 { 28 29 var message1 = "NotFound\r\n"; 30 var outbytes1 = Encoding.UTF8.GetBytes(message1); 31 c.Response.ContentType = "text/html; charset=utf-8"; 32 c.Response.Write(outbytes1, 0, outbytes1.Length); 33 return Next.Invoke(c); 34 } 35 36 // var urlPath = c.Request.Path; 37 // switch (urlPath) { 38 // .......... 39 // .......... 40 // 可以根據不同的URL PATH調用不同的處理方法 41 // 從而構成一個完整的應用。 42 // } 43 44 45 var message = "Welcome to My Home!"; 46 var outbytes = Encoding.UTF8.GetBytes(message); 47 c.Response.ContentType = "text/html; charset=utf-8"; 48 c.Response.Write(outbytes, 0, outbytes.Length); 49 50 return Task.FromResult<int>(0); 51 } 52 53 54 55 }
介紹:
1.構造函數第一個參數必須為 OwinMiddleware對象,可從Microsoft.Owin.dll源碼得知,這里不作話題。
2.我們在上面提到了“如果當前中間件無法匹配請求則會將請求轉向下一個中間件處理”,上面的代碼中的if如果成立,執行returnNext.Invoke(c);后會找注冊的下一個中間件,如果url匹配,會正確執行,並且執行return Task.FromResult<int>(0);結束當前請求。
2.新建類MyMiddleware2繼承OwinMiddleware並且實現Invoke函數,之所以建立兩個中間件,是為了演示”如果當前中間件無法匹配請求則會將請求轉向下一個中間件處理",同樣附上代碼
1 /// <summary> 2 /// OWIN "中間件" - MyMiddleware2 3 /// </summary> 4 public class MyMiddleware2 : OwinMiddleware 5 { 6 7 8 /// <summary> 9 /// 構造函數,第一個參數必須為 OwinMiddleware對象 ;第一個參數是固定的,后邊還可以添加自定義的其它參數 10 /// </summary> 11 /// <param name="next">下一個中間件</param> 12 public MyMiddleware2(OwinMiddleware next) 13 : base(next) 14 { 15 } 16 17 18 /// <summary> 19 /// 處理用戶請求的具體方法,該方法是必須的 20 /// </summary> 21 /// <param name="c">OwinContext對象</param> 22 /// <returns></returns> 23 public override Task Invoke(IOwinContext c) 24 { 25 26 if (Next != null && c.Request.Path.Value != "/user") 27 { 28 29 var message1 = "NotFound2!\r\n"; 30 var outbytes1 = Encoding.UTF8.GetBytes(message1); 31 c.Response.ContentType = "text/html; charset=utf-8"; 32 c.Response.Write(outbytes1, 0, outbytes1.Length); 33 return Task.FromResult(0); 34 } 35 36 // var urlPath = c.Request.Path; 37 // switch (urlPath) { 38 // .......... 39 // .......... 40 // 可以根據不同的URL PATH調用不同的處理方法 41 // 從而構成一個完整的應用。 42 // } 43 44 45 var message = "I'm MyMiddleware2"; 46 var outbytes = Encoding.UTF8.GetBytes(message); 47 c.Response.ContentType = "text/html; charset=utf-8"; 48 c.Response.Write(outbytes, 0, outbytes.Length); 49 50 return Task.FromResult<int>(0); 51 } 52 53 54 55 }
3.中間件注冊類,代碼如下:
/// <summary> /// 這個類是為AppBuilder添加一個名叫UseMyApp的擴展方法 /// </summary> public static class MyExtension { public static IAppBuilder UseMyApp(this IAppBuilder builder) { return builder.Use<MyMiddleware>(); //UseXXX可以帶多個參數,對應中間件構造函數中的第2、3、....參數; } public static IAppBuilder UseMyApp2(this IAppBuilder builder) { return builder.Use<MyMiddleware2>(); //UseXXX可以帶多個參數,對應中間件構造函數中的第2、3、....參數; } }
用過第三方Owin框架如Nancyfx的朋友是不是感覺比較熟悉,使用UseXXX()
4.注冊中間件,新建Startup類
1 public class Startup 2 { 3 public void Configuration(IAppBuilder app) 4 { 5 6 app.UseMyApp(); 7 8 app.UseMyApp2(); 9 10 } 11 }
備注:為了達到演示的目的,必須注意注冊時的順序,我們的Next.Invoke(c)是在MyMiddleware中編寫的而不是MyMiddleware2,所以必須讓MyMiddleware先執行,否則在MyMiddleware2 中遇到return Task.FromResult<int>(0);則直接結束當前請求。當然你也可以更換順序試試,后面會附上源碼下載
5.到目前為止,我們的代碼已經寫好,配置好TinyFox准備測試,如果不知道Tinyfox作為OwinHost如何調試請參考http://www.cnblogs.com/gaobing/p/4969581.html。
五、測試與總結, 並附上測試圖
1.不匹配的url
2.匹配的中間件2的url
3.匹配中間件1的url
備注:之所以不執行中間件2,是因為成功匹配url,所以直接return Task.FromResult<int>(0);結束當前請求
六、源碼地址
七、學習交流群