Middleware是OWIN管道的基本組成單元,最後拼接的OWIN管道來處理客戶端請求,輸出網頁。這篇文章,首先看看Web Form, MVC, Web API如何結合OWIN使用。 而後將如何編寫Middleware和編寫一個具體的Cache Middleware.web
閱讀目錄:編程
一. 原有的Web Form, MVC項目如何結合OWIN?api
1.1 經過路由配置,將程序分紅多個部分,一些部分由Asp.net Web Form或者MVC處理,另一部分由OWIN管道處理。
1.2 在Web Form, MVC以前插入OWIN緩存
二. Web API以Middleware註冊到OWIN管道
三. 自定義Cache Middlewareapp
3.1 HelloWorld Middleware
3.2 Cache Middlewareide
四,總結函數
一,原有的Web Form, MVC項目如何結合OWIN?
壞消息,很是抱歉,儘管OWIN是革命性的,可是Web Form和MVC如今還不能做爲一箇中間件集成到OWIN管道中。緣由在第一篇中Asp.net的歷史中有分析過,緣由就是Web Form和MVC依賴於System.Web.dll中的不少類型。而在OWIN管道中,是沒法提供這些依賴的。不過好消息是,在Asp.net vNext中,將會完全告別System.Web.dll依賴, 那個時候,Asp.net vNext將是集大成者。據說vNext項目組正在和Mono團隊一塊兒工做,使得Asp.net vNext開發的項目可以在*nix, osx系統上運行。post
那麼在當前的狀況下,OWIN和Web Form, MVC的結合開發通常是兩種形式:ui
1. 經過路由配置,將程序分紅多個部分,一些部分由Asp.net Web Form或者MVC處理,另一部分由OWIN管道處理。spa
// How to hook OWIN pipelines into the normal Asp.Net route table side by side with other components.
protected void Application_Start(object sender, EventArgs e)
{
//owin開頭的訪問路徑將會發送到startup.cs初始化的OWIN管道處理
RouteTable.Routes.MapOwinPath("/owin");
//special開頭的訪問路徑將會由OwinApp2管道來處理
RouteTable.Routes.MapOwinPath("/special", app =>
{
app.Run(OwinApp2.Invoke);
});
}
如上面代碼,在Application_Start函數或者路由配置函數中,分別爲/owin路徑和/special配置了不一樣的OWIN管道。
完整的代碼,請移步這裏http://aspnet.codeplex.com/sourcecontrol/latest#Samples/Katana/AspNetRoutes/Global.asax.cs
2. 在Web Form, MVC以前插入OWIN
在Web Form和MVC項目中,也能夠添加Startup.cs, 指定成爲OWIN的初始化類型,那麼請求會先通過OWIN管道處理,最後轉向Web Form或者MVC程序。這種方式,經常用來配置log, authentication, cache等等這些Middleware.
二,Web API以Middleware註冊到OWIN管道
Web API因爲無任何依賴於System.web.dll, 因此Web API能夠做爲Middleware註冊到OWIN管道中。
具體方法以下:
public class Startup
{
// Invoked once at startup to configure your application.
public void Configuration(IAppBuilder builder)
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("Default", "api/{controller}/{customerID}", new { controller = "Customer", customerID = RouteParameter.Optional });//定義web api route
//xml格式輸出結果
config.Formatters.XmlFormatter.UseXmlSerializer = true;
config.Formatters.Remove(config.Formatters.JsonFormatter);
// config.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;
//將web api以Middleware註冊到OWIN管道中
builder.UseWebApi(config);
}
}
三,自定義Cache Middleware
3.1 HelloWorld Middleware
先建一個Middleware, 經過繼承OwinMiddleware基類。這個Middleware的功能很是簡單,就是打印當前的系統時間。
public class HelloWorldMiddleware : OwinMiddleware
{
public HelloWorldMiddleware(OwinMiddleware next) : base(next)
{
}
public override Task Invoke(IOwinContext context)
{
var response = "Hello World! It is " + DateTime.Now;
context.Response.Write(response);
return Next.Invoke(context);
}
}
將該Middleware註冊到OWIN管道後,執行獲得的網頁:
只要咱們不斷的刷新網頁,每次顯示的時間都會不一樣,由於每次都會從新讀取系統時間,從新呈現頁面。
3.2 Cache Middleware
實現cache middleware的思路比較簡單,以訪問的Url爲key, 以輸出的內容爲value。第一次訪問的時候,會緩存下來輸出的內容,在下次訪問的時候,將直接返回緩存的內容,而不是從新生成。具體代碼以下:
public class CacheMiddleware : OwinMiddleware
{
private readonly IDictionary<string, CacheItem> _responseCache = new Dictionary<string, CacheItem>(); //Cache存儲的字典
public CacheMiddleware(OwinMiddleware next)
: base(next)
{
}
public override Task Invoke(IOwinContext context)
{
context.Environment["caching.addToCache"] = new Action<IOwinContext, string, TimeSpan>(AddToCache);
var path = context.Request.Path.Value;
//若是訪問的路徑沒有緩存,就傳遞到OWIN管道的下一層中處理
if (!_responseCache.ContainsKey(path)) {
return Next.Invoke(context);
}
var cacheItem = _responseCache[path];
//檢查緩存是否到期
if (cacheItem.ExpiryTime <= DateTime.Now)
{
_responseCache.Remove(path);
return Next.Invoke(context);
}
//直接從緩存中輸出,而不是從新render頁面
context.Response.Write(cacheItem.Response);
return Task.FromResult(0);
}
//添加cache的方法,將會以委託的方式存放到OWIN管道字典中,這樣任何OWIN的Middleware都可以調用,從而保存數據到緩存
public void AddToCache(IOwinContext context, string response, TimeSpan cacheDuration)
{
_responseCache[context.Request.Path.Value] = new CacheItem { Response = response, ExpiryTime = DateTime.Now + cacheDuration };
}
private class CacheItem
{
public string Response { get; set; }//保存緩存的內容
public DateTime ExpiryTime { get; set; }//肯定緩存的時間
}
}
View Code
接下來,咱們要改造HelloWorldMiddleware, 在HelloWorldMiddleware輸出後,咱們把輸出的內容保存到Cache中。具體代碼以下:
public class HelloWorldMiddleware : OwinMiddleware
{
public HelloWorldMiddleware(OwinMiddleware next) : base(next)
{
}
public override Task Invoke(IOwinContext context)
{
var response = "Hello World! It is " + DateTime.Now;
if (context.Environment.ContainsKey("caching.addToCache"))//這裏直接從OWIN管道的字典中,檢查是否有add cache, 若是存在,就將輸出內容緩存到cache中,過時時間爲10分鐘。
{
var addToCache = (Action<IOwinContext, string, TimeSpan>)context.Environment["caching.addToCache"];
addToCache(context, response, TimeSpan.FromMinutes(10));
}
context.Response.Write(response);
return Task.FromResult(0);
}
}
View Code
最後,將CacheMiddleware添加到OWIN管道中發揮做用,注意註冊管道的順序問題,Middleware是必定要在HelloWorldMiddleware以前的。
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Use<CacheMiddleware>();
app.Use<HelloWorldMiddleware>();
}
}
四,總結
經過上面的示例,但願對你們如何編寫Middleware有些基本的概念。
OWIN的優點在上面的例子中應該有些體現,就是Middleware之間經過數據和行爲規範, 你們能夠一塊兒無縫地協同工做,任何第三方的Middleware均可以很是簡單的集成到OWIN管道中,這應該是OWIN最大的魅力所在,開放的魅力。
同時, OWIN的目標是將Web Form, MVC, Web API統一到一個大的平臺下,這將更加有助於混合編程。