1】開(kāi)篇介紹
這篇文章將簡(jiǎn)單的分析一下有關(guān)靜態(tài)文件捆綁的ASP.NET組件System.Web.Optimization的運(yùn)行原理及基本的緩存問(wèn)題:
在我們的項(xiàng)目里面充斥著很多靜態(tài)文件,為了追求模塊化、插件化很多靜態(tài)文件都被設(shè)計(jì)成模塊的方式或者被分解,在需要的時(shí)候在通過(guò)組合的方式在UI層上使用;這就帶來(lái)一個(gè)問(wèn)題,文件多了會(huì)影響瀏覽器加載頁(yè)面的速度,而且由于瀏覽器的并發(fā)限制,對(duì)于并行的請(qǐng)求不是無(wú)限制的,所以捆綁靜態(tài)文件的功能就產(chǎn)生;其實(shí)在以前,IIS還沒(méi)有集成管道模型的時(shí)候我們只能通過(guò)動(dòng)態(tài)資源的方式進(jìn)行輸出,也就是我們經(jīng)常在*aspx頁(yè)面里看見(jiàn)很多*.axd結(jié)尾的請(qǐng)求,當(dāng)然多數(shù)情況下是配合ASP.NETAJAX用來(lái)輸出動(dòng)態(tài)JS、HTMDOM、CSS用的;
最新的IIS已經(jīng)很好的集成了ASP.NET管道模型,也就是說(shuō)我們完全可以通過(guò)ASP.NET本身的擴(kuò)展來(lái)控制所有經(jīng)過(guò)IIS的請(qǐng)求,包括靜態(tài)文件,所以讓捆綁靜態(tài)文件成為了可能;
下面我們將分析一下System.Web.Optimization組件的基本運(yùn)行原理,它是如何動(dòng)態(tài)加載的,如何控制緩存的;
2】System.Web.Optimization 組件
每當(dāng)我們新建一個(gè)ASP.NETMVC4站點(diǎn)的時(shí)候都會(huì)在~/App_Start目錄下有一個(gè)BundleConfig.cs的啟動(dòng)文件,當(dāng)然創(chuàng)建其他的ASP.NET4.0及4.0以上的項(xiàng)目也會(huì)有;
我第一次看見(jiàn)這個(gè)文件實(shí)在讓我困惑,所以我打算簡(jiǎn)單的分析一下,知道其基本原理;
代碼是一個(gè)靜態(tài)方法,然后傳入一個(gè)BundleCollection集合對(duì)象,其實(shí)就是Bundle對(duì)象的集合,然后通過(guò)向集合內(nèi)部注冊(cè)多個(gè)Bundle;每個(gè)Bundle對(duì)應(yīng)著多個(gè)靜態(tài)文件,可以想象成就是鍵值對(duì)集合;通過(guò)后面的Include方法包含N多個(gè)靜態(tài)文件,這里的靜態(tài)文件路徑可以是符合特定規(guī)則的字符串,由它內(nèi)部去計(jì)算;
這是注冊(cè)階段,然后就是使用階段,使用階段很簡(jiǎn)單只要我們通過(guò)我們注冊(cè)的Key字符串就能直接引用這些靜態(tài)文件列表;
我們只要關(guān)注Styles.Render、Scripts.Render兩個(gè)方法,這兩個(gè)方法是想頁(yè)面注入之前在后臺(tái)配置的靜態(tài)文件列表;這樣我們?cè)诳蛻舳丝匆?jiàn)的就是被捆綁過(guò)后的文件集合了;
文件的連接地址已經(jīng)是被捆綁過(guò)后的地址了,這個(gè)地址就是我們?cè)谥白?cè)的時(shí)候用的key,后面它需要這個(gè)key去獲取value 靜態(tài)文件列表;要想你的捆綁起效果需要在注冊(cè)的時(shí)候加上一段:BundleTable.EnableOptimizations = true;代碼,意思是說(shuō)開(kāi)啟捆綁,如果不開(kāi)啟捆綁則默認(rèn)在調(diào)試環(huán)境里將不起效果,因?yàn)镾ystem.Web.Optimization使用了默認(rèn)捆綁策略,如果是在Debug模式下,將不啟用捆綁,如果你人為的設(shè)置了將覆蓋默認(rèn)設(shè)置;
使用就是這些,下面我們需要搞懂它是如何運(yùn)行的,要了解一下它的基本原理;
3】System.Web.Optimization 組件基本原理
既然IIS集成了管道模型,那么我們肯定是能找到對(duì)應(yīng)的HttpModule的,為了節(jié)省時(shí)間我就不去下載源碼了,我們直接用反編譯工具看一下;
這就是Bundle的HttpModule,它只用來(lái)處理
Bundle的連接地址,雖然它在HTTP的管道中;找到它就好順藤摸瓜了,但是奇怪的是我在Web.config里沒(méi)有發(fā)現(xiàn)它的配置信息,奇怪了,難道它還跑去系統(tǒng)文件改,當(dāng)然是不可能的;所以我一時(shí)還想不起能有什么辦法動(dòng)態(tài)注冊(cè),提起動(dòng)態(tài)注冊(cè)突然有了思路,好像有一個(gè)Assembly級(jí)別的特性用來(lái)注冊(cè)Application_Start啟動(dòng)時(shí)候的前置代碼,會(huì)在Application啟動(dòng)之前執(zhí)行,來(lái)看一下;
果然藏著這里呢,它注冊(cè)了一個(gè)PreApplicationStartCode靜態(tài)類(lèi),使用Start方法啟動(dòng);
這段代碼很簡(jiǎn)單,先判斷有沒(méi)有執(zhí)行過(guò)注冊(cè),如果沒(méi)有就執(zhí)行動(dòng)態(tài)注冊(cè),這個(gè)動(dòng)態(tài)注冊(cè)組件是.NETFramework自帶的,在Microsoft.Web.Infrastructure里面只不過(guò)屬于平臺(tái)相關(guān)的,跟ASP.NET沒(méi)有直接關(guān)系,我們可以用Microsoft.Web.Infrastructure來(lái)開(kāi)發(fā)自己的WEB組件;這里有一個(gè)疑問(wèn),為什么靜態(tài)方法也要加判斷呢,不是只會(huì)執(zhí)行一次嗎,因?yàn)殪o態(tài)方法的執(zhí)行是不受控制的,所以如果不加判斷很有可能會(huì)注冊(cè)多次,出于嚴(yán)謹(jǐn)考慮還是加上;
現(xiàn)在基本上我們已經(jīng)找到源頭了,服務(wù)端這里我們先放一下,對(duì)于客戶端的疑問(wèn)很多,它既然幫我們捆綁了,那么緩存是如何處理的,也就是說(shuō)它的輸出緩存有沒(méi)有設(shè)置,如果設(shè)置了不是有問(wèn)題;
【客戶端緩存相關(guān)】
為了很好的了解請(qǐng)求之間的信息,我們用Fiddler監(jiān)聽(tīng)一下;
我們看見(jiàn)它的Cache部分是用了If-Modified-Since來(lái)表示本地的文件的最后一次修改,這樣是為了能夠讓服務(wù)器去驗(yàn)證文件是否改動(dòng),如果沒(méi)有改動(dòng)服務(wù)器的響應(yīng)狀態(tài)碼為304,說(shuō)明Bundle在輸出的時(shí)候并沒(méi)有設(shè)置對(duì)這個(gè)文件進(jìn)行客戶端強(qiáng)制緩存,我們通過(guò)Pragma: no-cache頭也能看出來(lái)了;
那么我們得出結(jié)論,所有Bundle出來(lái)的文件都不可能直接緩存在瀏覽器中,每次都會(huì)帶上Cache段If-Modified-Since去驗(yàn)證服務(wù)器的文件版本;剛好這里我們可以跟動(dòng)態(tài)輸出的靜態(tài)文件地址的后面的參數(shù)對(duì)上了;
比如:
/Content/css?v=ZPnWVRT3c0yyrVDPmI-xkJuhBdJfQsL3A0K5C9WTOk01
這個(gè)鏈接后面的v參數(shù)是表示當(dāng)前Bundle后虛擬文件的版本,如果我們?cè)诜?wù)器上把文件修改了之后那么這個(gè)文件的If-Modified-Since驗(yàn)證就失敗了,會(huì)生成新的版本號(hào)作為連接的參數(shù);我們來(lái)看一下,心里踏實(shí);
我加了一個(gè)width:auto的style,那么這個(gè)時(shí)候我刷新客戶端應(yīng)該是不會(huì)再有304出現(xiàn)了;
顯然/Content/css?v=doYFOk3BdOYWDIRbQ7juV6eQdlJAu6RtC0G13El7X041 文件的版本變了,那么Response也不應(yīng)該是304了;
如果靜態(tài)文件的版本號(hào)發(fā)生改變,根本就不會(huì)帶上 If-Modified-Since,這個(gè)是用在每次進(jìn)行進(jìn)行Post是用來(lái)驗(yàn)證的;其實(shí)意思就是說(shuō)如果沒(méi)有IIS集成模式那么捆綁文件的方式只能改變靜態(tài)文件的文件名;
4】擴(kuò)展自定義類(lèi)型靜態(tài)文件
Bundle對(duì)象是所有需要捆綁文件的基類(lèi),如果我們需要擴(kuò)展一些靜態(tài)文件,如一些特定領(lǐng)域的靜態(tài)文件,我們可以直接繼承這個(gè)類(lèi);
【XML文件的緩存】
擴(kuò)展XML文件很簡(jiǎn)單,我們只需要繼承一下Bundle對(duì)象,所有關(guān)于動(dòng)態(tài)生成URL都有專(zhuān)門(mén)的對(duì)象處理,我們來(lái)看下代碼;
public class XmlBundle : Bundle
{
public XmlBundle(string path) : base(path) { }
}
public static class XmlBundleRender
{
public static IHtmlString Render(string path)
{
BundleResolver bundle = new BundleResolver(BundleTable.Bundles);
return new HtmlString(
string.Format(@"link href=""{0}"" rel=""stylesheet""/>", bundle.GetBundleUrl(path)));
}
}
首先我們需要一個(gè)繼承自Bundle對(duì)象的XmlBundle,用來(lái)表示我們所有將要傳輸?shù)腦ML文件捆綁容器,然后我們需要一個(gè)靜態(tài)方法用來(lái)注冊(cè)捆綁后的URL;
這個(gè)URL的生成有專(zhuān)門(mén)的BundleResolver對(duì)象來(lái)完成,我們只需要傳入所有的BundleCollection對(duì)象,我這里為了能在瀏覽器中測(cè)試所以寫(xiě)了一段stylesheet類(lèi)型的link;這樣我們就能直接在我們需要的地方直接使用了,我在index視圖中引用:@MvcApplication4.Seed.XmlBundleRender.Render("~/custom/xml");是不是很簡(jiǎn)單,這樣我們就能對(duì)所有想控制捆綁的文件進(jìn)行捆綁,只需要繼承加簡(jiǎn)單的靜態(tài)方法輔助;
我們來(lái)看一下我們的XML文件是否具有所有緩存特性;
第一次請(qǐng)求沒(méi)有加If-Modified-Since段,返回的內(nèi)容是一個(gè)簡(jiǎn)單的model>222/model> 測(cè)試簡(jiǎn)單,現(xiàn)在我們看它是否在下一次不改變內(nèi)容的情況下使用緩存;
在我們預(yù)料之中,使用了緩存數(shù)據(jù),下面我們需要把服務(wù)器上的XML文件進(jìn)行修改,將222改成243454637看是否自動(dòng)刷新本地緩存也就是說(shuō)不會(huì)是304返回狀態(tài);
也刷新緩存,符合理論根據(jù),正確的返回了我們修改后的值;
結(jié):其實(shí)HTTP不僅僅用在瀏覽器中,會(huì)有很多使用HTTP的場(chǎng)合,所以我們能很好的將這種功能用來(lái)捆綁一些圖片、文字等多種場(chǎng)合中,確實(shí)是個(gè)不錯(cuò)的組件;文章結(jié)束,謝謝;
作者:王清培
出處:http://www.cnblogs.com/wangiqngpei557/
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
您可能感興趣的文章:- 無(wú)法將類(lèi)型為“System.Web.UI.WebControls.HiddenField”的對(duì)象強(qiáng)制轉(zhuǎn)換為類(lèi)型的錯(cuò)誤的解決
- System.Web.Routing入門(mén)及進(jìn)階
- System.Web.Routing入門(mén)及進(jìn)階
- NET Runtime Optimization Service 1101 錯(cuò)誤的解決方法
- ASP.NET MVC命名空間時(shí)引起錯(cuò)誤的解決方法
- ASP.Net中命名空間Namespace淺析和使用例子
- System.Web中不存在類(lèi)型或命名空間名稱(chēng)“Optimization”(是否缺少程序集引用?)