天天看點

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

這篇文章将簡單的分析一下有關靜态檔案捆綁的ASP.NET元件System.Web.Optimization的運作原理及基本的緩存問題; 在我們的項目裡面充斥着很多靜态檔案,為了追求子產品化、插件化很多靜态檔案都被設計成子產品的方式或者被分解,在需要的時候在通過組合的方式在UI層上使用;這就帶來一個問題,檔案多了會影響浏覽器加載頁面的速度,而且由于浏覽器的并發限制,對于并行....

閱讀目錄:

  • 1.開篇介紹
  • 2.System.Web.Optimization 元件
  • 3.System.Web.Optimization 元件基本原理
  • 4.擴充自定義類型靜态檔案

1】開篇介紹

這篇文章将簡單的分析一下有關靜态檔案捆綁的ASP.NET元件System.Web.Optimization的運作原理及基本的緩存問題;

在我們的項目裡面充斥着很多靜态檔案,為了追求子產品化、插件化很多靜态檔案都被設計成子產品的方式或者被分解,在需要的時候在通過組合的方式在UI層上使用;這就帶來一個問題,檔案多了會影響浏覽器加載頁面的速度,而且由于浏覽器的并發限制,對于并行的請求不是無限制的,是以捆綁靜态檔案的功能就産生;其實在以前,IIS還沒有內建管道模型的時候我們隻能通過動态資源的方式進行輸出,也就是我們經常在*aspx頁面裡看見很多*.axd結尾的請求,當然多數情況下是配合ASP.NETAJAX用來輸出動态JS、HTMDOM、CSS用的;

最新的IIS已經很好的內建了ASP.NET管道模型,也就是說我們完全可以通過ASP.NET本身的擴充來控制所有經過IIS的請求,包括靜态檔案,是以讓捆綁靜态檔案成為了可能;

下面我們将分析一下System.Web.Optimization元件的基本運作原理,它是如何動态加載的,如何控制緩存的;

2】System.Web.Optimization 元件

每當我們建立一個ASP.NETMVC4站點的時候都會在~/App_Start目錄下有一個BundleConfig.cs的啟動檔案,當然建立其他的ASP.NET4.0及4.0以上的項目也會有;

我第一次看見這個檔案實在讓我困惑,是以我打算簡單的分析一下,知道其基本原理;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

代碼是一個靜态方法,然後傳入一個BundleCollection集合對象,其實就是Bundle對象的集合,然後通過向集合内部注冊多個Bundle;每個Bundle對應着多個靜态檔案,可以想象成就是鍵值對集合;通過後面的Include方法包含N多個靜态檔案,這裡的靜态檔案路徑可以是符合特定規則的字元串,由它内部去計算;

這是注冊階段,然後就是使用階段,使用階段很簡單隻要我們通過我們注冊的Key字元串就能直接引用這些靜态檔案清單;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

我們隻要關注Styles.Render、Scripts.Render兩個方法,這兩個方法是想頁面注入之前在背景配置的靜态檔案清單;這樣我們在用戶端看見的就是被捆綁過後的檔案集合了;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

檔案的連接配接位址已經是被捆綁過後的位址了,這個位址就是我們在之前注冊的時候用的key,後面它需要這個key去擷取value 靜态檔案清單;要想你的捆綁起效果需要在注冊的時候加上一段:BundleTable.EnableOptimizations = true;代碼,意思是說開啟捆綁,如果不開啟捆綁則預設在調試環境裡将不起效果,因為System.Web.Optimization使用了預設捆綁政策,如果是在Debug模式下,将不啟用捆綁,如果你人為的設定了将覆寫預設設定;

使用就是這些,下面我們需要搞懂它是如何運作的,要了解一下它的基本原理;

3】System.Web.Optimization 元件基本原理

既然IIS內建了管道模型,那麼我們肯定是能找到對應的HttpModule的,為了節省時間我就不去下載下傳源碼了,我們直接用反編譯工具看一下;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

這就是Bundle的HttpModule,它隻用來處理

Bundle的連接配接位址,雖然它在HTTP的管道中;找到它就好順藤摸瓜了,但是奇怪的是我在Web.config裡沒有發現它的配置資訊,奇怪了,難道它還跑去系統檔案改,當然是不可能的;是以我一時還想不起能有什麼辦法動态注冊,提起動态注冊突然有了思路,好像有一個Assembly級别的特性用來注冊Application_Start啟動時候的前置代碼,會在Application啟動之前執行,來看一下;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

果然藏着這裡呢,它注冊了一個PreApplicationStartCode靜态類,使用Start方法啟動;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

這段代碼很簡單,先判斷有沒有執行過注冊,如果沒有就執行動态注冊,這個動态注冊元件是.NETFramework自帶的,在Microsoft.Web.Infrastructure裡面隻不過屬于平台相關的,跟ASP.NET沒有直接關系,我們可以用Microsoft.Web.Infrastructure來開發自己的WEB元件;這裡有一個疑問,為什麼靜态方法也要加判斷呢,不是隻會執行一次嗎,因為靜态方法的執行是不受控制的,是以如果不加判斷很有可能會注冊多次,出于嚴謹考慮還是加上;

現在基本上我們已經找到源頭了,服務端這裡我們先放一下,對于用戶端的疑問很多,它既然幫我們捆綁了,那麼緩存是如何處理的,也就是說它的輸出緩存有沒有設定,如果設定了不是有問題;

【用戶端緩存相關】

為了很好的了解請求之間的資訊,我們用Fiddler監聽一下;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

我們看見它的Cache部分是用了If-Modified-Since來表示本地的檔案的最後一次修改,這樣是為了能夠讓伺服器去驗證檔案是否改動,如果沒有改動伺服器的響應狀态碼為304,說明Bundle在輸出的時候并沒有設定對這個檔案進行用戶端強制緩存,我們通過Pragma: no-cache頭也能看出來了;

那麼我們得出結論,所有Bundle出來的檔案都不可能直接緩存在浏覽器中,每次都會帶上Cache段If-Modified-Since去驗證伺服器的檔案版本;剛好這裡我們可以跟動态輸出的靜态檔案位址的後面的參數對上了;

比如:

/Content/css?v=ZPnWVRT3c0yyrVDPmI-xkJuhBdJfQsL3A0K5C9WTOk01

這個連結後面的v參數是表示目前Bundle後虛拟檔案的版本,如果我們在伺服器上把檔案修改了之後那麼這個檔案的If-Modified-Since驗證就失敗了,會生成新的版本号作為連接配接的參數;我們來看一下,心裡踏實;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

我加了一個width:auto的style,那麼這個時候我重新整理用戶端應該是不會再有304出現了;

顯然/Content/css?v=doYFOk3BdOYWDIRbQ7juV6eQdlJAu6RtC0G13El7X041 檔案的版本變了,那麼Response也不應該是304了;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)
.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

如果靜态檔案的版本号發生改變,根本就不會帶上 If-Modified-Since,這個是用在每次進行進行Post是用來驗證的;其實意思就是說如果沒有IIS內建模式那麼捆綁檔案的方式隻能改變靜态檔案的檔案名;

4】擴充自定義類型靜态檔案

Bundle對象是所有需要捆綁檔案的基類,如果我們需要擴充一些靜态檔案,如一些特定領域的靜态檔案,我們可以直接繼承這個類;

【XML檔案的緩存】

擴充XML檔案很簡單,我們隻需要繼承一下Bundle對象,所有關于動态生成URL都有專門的對象處理,我們來看下代碼;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)
.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)
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    }      

View Code

首先我們需要一個繼承自Bundle對象的XmlBundle,用來表示我們所有将要傳輸的XML檔案捆綁容器,然後我們需要一個靜态方法用來注冊捆綁後的URL;

這個URL的生成有專門的BundleResolver對象來完成,我們隻需要傳入所有的BundleCollection對象,我這裡為了能在浏覽器中測試是以寫了一段stylesheet類型的link;這樣我們就能直接在我們需要的地方直接使用了,我在index視圖中引用:@MvcApplication4.Seed.XmlBundleRender.Render("~/custom/xml");是不是很簡單,這樣我們就能對所有想控制捆綁的檔案進行捆綁,隻需要繼承加簡單的靜态方法輔助;

我們來看一下我們的XML檔案是否具有所有緩存特性;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

第一次請求沒有加If-Modified-Since段,傳回的内容是一個簡單的<model>222</model> 測試簡單,現在我們看它是否在下一次不改變内容的情況下使用緩存;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

在我們預料之中,使用了緩存資料,下面我們需要把伺服器上的XML檔案進行修改,将222改成243454637看是否自動重新整理本地緩存也就是說不會是304傳回狀态;

.NET/ASP.NET 4.5 Bundle元件(捆綁、縮小靜态檔案)

也重新整理緩存,符合理論根據,正确的傳回了我們修改後的值;

結:其實HTTP不僅僅用在浏覽器中,會有很多使用HTTP的場合,是以我們能很好的将這種功能用來捆綁一些圖檔、文字等多種場合中,确實是個不錯的元件;文章結束,謝謝;

作者:王清培

出處:http://www.cnblogs.com/wangiqngpei557/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。