閱讀目錄:css
這篇文章將簡單的分析一下有關靜態文件捆綁的ASP.NET組件System.Web.Optimization的運行原理及基本的緩存問題;瀏覽器
在咱們的項目裏面充斥着不少靜態文件,爲了追求模塊化、插件化不少靜態文件都被設計成模塊的方式或者被分解,在須要的時候在經過組合的方式在UI層上使用;這就帶來一個問題,文件多了會影響瀏覽器加載頁面的速度,並且因爲瀏覽器的併發限制,對於並行的請求不是無限制的,因此捆綁靜態文件的功能就產生;其實在之前,IIS尚未集成管道模型的時候咱們只能經過動態資源的方式進行輸出,也就是咱們常常在*aspx頁面裏看見不少*.axd結尾的請求,固然多數狀況下是配合ASP.NETAJAX用來輸出動態JS、HTMDOM、CSS用的;緩存
最新的IIS已經很好的集成了ASP.NET管道模型,也就是說咱們徹底能夠經過ASP.NET自己的擴展來控制全部通過IIS的請求,包括靜態文件,因此讓捆綁靜態文件成爲了可能;服務器
下面咱們將分析一下System.Web.Optimization組件的基本運行原理,它是如何動態加載的,如何控制緩存的;併發
每當咱們新建一個ASP.NETMVC4站點的時候都會在~/App_Start目錄下有一個BundleConfig.cs的啓動文件,固然建立其餘的ASP.NET4.0及4.0以上的項目也會有;ide
我第一次看見這個文件實在讓我困惑,因此我打算簡單的分析一下,知道其基本原理;模塊化
代碼是一個靜態方法,而後傳入一個BundleCollection集合對象,其實就是Bundle對象的集合,而後經過向集合內部註冊多個Bundle;每一個Bundle對應着多個靜態文件,能夠想象成就是鍵值對集合;經過後面的Include方法包含N多個靜態文件,這裏的靜態文件路徑能夠是符合特定規則的字符串,由它內部去計算;工具
這是註冊階段,而後就是使用階段,使用階段很簡單隻要咱們經過咱們註冊的Key字符串就能直接引用這些靜態文件列表;測試
咱們只要關注Styles.Render、Scripts.Render兩個方法,這兩個方法是想頁面注入以前在後臺配置的靜態文件列表;這樣咱們在客戶端看見的就是被捆綁事後的文件集合了;spa
文件的鏈接地址已是被捆綁事後的地址了,這個地址就是咱們在以前註冊的時候用的key,後面它須要這個key去獲取value 靜態文件列表;要想你的捆綁起效果須要在註冊的時候加上一段:BundleTable.EnableOptimizations = true;代碼,意思是說開啓捆綁,若是不開啓捆綁則默認在調試環境裏將不起效果,由於System.Web.Optimization使用了默認捆綁策略,若是是在Debug模式下,將不啓用捆綁,若是你人爲的設置了將覆蓋默認設置;
使用就是這些,下面咱們須要搞懂它是如何運行的,要了解一下它的基本原理;
既然IIS集成了管道模型,那麼咱們確定是能找到對應的HttpModule的,爲了節省時間我就不去下載源碼了,咱們直接用反編譯工具看一下;
這就是Bundle的HttpModule,它只用來處理
Bundle的鏈接地址,雖然它在HTTP的管道中;找到它就好順藤摸瓜了,可是奇怪的是我在Web.config裏沒有發現它的配置信息,奇怪了,難道它還跑去系統文件改,固然是不可能的;因此我一時還想不起能有什麼辦法動態註冊,提起動態註冊忽然有了思路,好像有一個Assembly級別的特性用來註冊Application_Start啓動時候的前置代碼,會在Application啓動以前執行,來看一下;
果真藏着這裏呢,它註冊了一個PreApplicationStartCode靜態類,使用Start方法啓動;
這段代碼很簡單,先判斷有沒有執行過註冊,若是沒有就執行動態註冊,這個動態註冊組件是.NETFramework自帶的,在Microsoft.Web.Infrastructure裏面只不過屬於平臺相關的,跟ASP.NET沒有直接關係,咱們能夠用Microsoft.Web.Infrastructure來開發本身的WEB組件;這裏有一個疑問,爲何靜態方法也要加判斷呢,不是隻會執行一次嗎,由於靜態方法的執行是不受控制的,因此若是不加判斷頗有可能會註冊屢次,出於嚴謹考慮仍是加上;
如今基本上咱們已經找到源頭了,服務端這裏咱們先放一下,對於客戶端的疑問不少,它既然幫咱們捆綁了,那麼緩存是如何處理的,也就是說它的輸出緩存有沒有設置,若是設置了不是有問題;
爲了很好的瞭解請求之間的信息,咱們用Fiddler監聽一下;
咱們看見它的Cache部分是用了If-Modified-Since來表示本地的文件的最後一次修改,這樣是爲了可以讓服務器去驗證文件是否改動,若是沒有改動服務器的響應狀態碼爲304,說明Bundle在輸出的時候並無設置對這個文件進行客戶端強制緩存,咱們經過Pragma: no-cache頭也能看出來了;
那麼咱們得出結論,全部Bundle出來的文件都不可能直接緩存在瀏覽器中,每次都會帶上Cache段If-Modified-Since去驗證服務器的文件版本;恰好這裏咱們能夠跟動態輸出的靜態文件地址的後面的參數對上了;
好比:
/Content/css?v=ZPnWVRT3c0yyrVDPmI-xkJuhBdJfQsL3A0K5C9WTOk01
這個連接後面的v參數是表示當前Bundle後虛擬文件的版本,若是咱們在服務器上把文件修改了以後那麼這個文件的If-Modified-Since驗證就失敗了,會生成新的版本號做爲鏈接的參數;咱們來看一下,內心踏實;
我加了一個width:auto的style,那麼這個時候我刷新客戶端應該是不會再有304出現了;
顯然/Content/css?v=doYFOk3BdOYWDIRbQ7juV6eQdlJAu6RtC0G13El7X041 文件的版本變了,那麼Response也不該該是304了;
若是靜態文件的版本號發生改變,根本就不會帶上 If-Modified-Since,這個是用在每次進行進行Post是用來驗證的;其實意思就是說若是沒有IIS集成模式那麼捆綁文件的方式只能改變靜態文件的文件名;
Bundle對象是全部須要捆綁文件的基類,若是咱們須要擴展一些靜態文件,如一些特定領域的靜態文件,咱們能夠直接繼承這個類;
【XML文件的緩存】
擴展XML文件很簡單,咱們只須要繼承一下Bundle對象,全部關於動態生成URL都有專門的對象處理,咱們來看下代碼;
1 public class XmlBundle : Bundle 2 { 3 public XmlBundle(string path) : base(path) { } 4 } 5 public static class XmlBundleRender 6 { 7 public static IHtmlString Render(string path) 8 { 9 BundleResolver bundle = new BundleResolver(BundleTable.Bundles); 10 return new HtmlString( 11 string.Format(@"<link href=""{0}"" rel=""stylesheet""/>", bundle.GetBundleUrl(path))); 12 } 13 }
首先咱們須要一個繼承自Bundle對象的XmlBundle,用來表示咱們全部將要傳輸的XML文件捆綁容器,而後咱們須要一個靜態方法用來註冊捆綁後的URL;
這個URL的生成有專門的BundleResolver對象來完成,咱們只須要傳入全部的BundleCollection對象,我這裏爲了能在瀏覽器中測試因此寫了一段stylesheet類型的link;這樣咱們就能直接在咱們須要的地方直接使用了,我在index視圖中引用:@MvcApplication4.Seed.XmlBundleRender.Render("~/custom/xml");是否是很簡單,這樣咱們就能對全部想控制捆綁的文件進行捆綁,只須要繼承加簡單的靜態方法輔助;
咱們來看一下咱們的XML文件是否具備全部緩存特性;
第一次請求沒有加If-Modified-Since段,返回的內容是一個簡單的<model>222</model> 測試簡單,如今咱們看它是否在下一次不改變內容的狀況下使用緩存;
在咱們預料之中,使用了緩存數據,下面咱們須要把服務器上的XML文件進行修改,將222改爲243454637看是否自動刷新本地緩存也就是說不會是304返回狀態;
也刷新緩存,符合理論根據,正確的返回了咱們修改後的值;
結:其實HTTP不只僅用在瀏覽器中,會有不少使用HTTP的場合,因此咱們能很好的將這種功能用來捆綁一些圖片、文字等多種場合中,確實是個不錯的組件;文章結束,謝謝;
做者:王清培
出處:http://www.cnblogs.com/wangiqngpei557/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,不然保留追究法律責任的權利。