ASP.NET沒有魔法——ASP.NET MVC Razor與View渲染 ASP.NET沒有魔法——ASP.NET MVC界面美化及使用Bundle完成靜態資源管理

ASP.NET沒有魔法——ASP.NET MVC Razor與View渲染

 

  對於Web應用來講,它的界面是由瀏覽器根據HTML代碼及其引用的相關資源進行渲染後展現給用戶的結果,換句話說Web應用的界面呈現工做是由瀏覽器完成的,Web應用的原理是經過Http協議從服務器上獲取到對應的Html代碼以及相關資源,使得瀏覽器可以完成正確的呈現工做。css

  ASP.NET MVC做爲一個Web應用構建框架View承擔了UI顯示的功能,在開發過程當中View以Action的名稱命名,當用戶的請求被路由到某一Action方法時,ASP.NET MVC將會根據Action的名稱來獲取到對應的View文件,將該View文件動態處理後生成最終的Html內容,將內容返回到瀏覽器進行顯示。因此ASP.NET的渲染實際上指的是動態的生成Html代碼的過程。
  而ASP.NET MVC中action的代碼能夠簡單以下:html

   

  僅須要調用一個View方法就能夠將Index這個View顯示到用戶的瀏覽器上,那麼View方法到底作了什麼處理?Razor是什麼?Action方法的返回值ActionResult又是什麼?
  本文將從如下幾個方面來介紹ASP.NET MVC Html代碼的生成過程:
  ● ActionResult及ViewResult
  ● View的查找與Razor
    ○ ViewEngineCollection&ViewEngine
    ○ ViewEngineResult
  ● View的編譯與激活
  ● View的渲染
  ● 使用示例代碼演示View的渲染過程
  ● View的Html Helper與ModelMetadata
  ● 經常使用的ActionResult
  ● 小結前端

ActionResult及ViewResult

  在以前的文章《ASP.NET沒有魔法——ASP.NET MVC 過濾器(Filter)》中提到過,Action方法是由ActionInvoker完成執行的,Action返回的結果是一個ActionResult類型,Action執行後ActionInvoker又調用了ActionResult的ExecuteResult方法完成特定的操做,相關代碼以下所示:jquery

  

  

  ActionResult的定義以下,它包含了一個名爲ExecuteResult的方法,該方法用來完成對action方法執行結果進行處理:git

  

  回到最初提到的View()方法,該方法定義在Controller中,它的返回值是一個ViewResult類型:github

  

  能夠這麼說,當Action執行完成後,ASP.NET MVC的View渲染工做是由ViewResult在ExecuteResult方法中完成的,ViewResult的ExecuteResult實現代碼以下(注:該代碼在ViewResult的基類ViewResultBase中實現):web

  

  從代碼中能夠容易的看出,ASP.NET MVC中View的渲染工做主要有四步:
  1. 若是沒有指定View的名稱,那麼默認以Action的名稱爲View名稱。
  2. 根據控制器的上下文查找並得到真實的View對象。
  3. 調用View對象的Render方法將View的內容寫到HttpContext的響應信息中,後續將其返回至瀏覽器。
  4. 釋放View對象。ajax

  根據上面的分析View渲染的兩個重要步驟就是View對象的查找渲染,其整個過程可參考下圖,詳細內容將在後續介紹:編程

  

View的查找與Razor

  在ASP.NET MVC中View文件通常放置在項目根目錄的Views目錄下,以Controller名稱爲子目錄,每個子目錄下保存了以action方法名稱命名的View文件:bootstrap

  

  ViewResult類型中查找View的代碼以下:

  

  從代碼能夠看出它是經過一個ViewEngineCollection對象,根據ViewName(默認是actionName)去查找View的,若是找到返回一個ViewEngineResult類型,不然將拋出異常,異常中包含查找的位置:

  

   注:從上面的錯誤信息中能夠看到ASP.NET MVC在查找View時,除了匹配了.cshtml和.vbhtml的文件外,還匹配了.aspx和.ascx的文件,後者是Web Form框架的頁面文件,這是爲何呢?由於默認狀況下ASP.NET MVC中會包含MVC使用的Razor 引擎和Web Form使用的Web Form引擎,因此在純使用MVC開發的狀況下,爲了優化性能,通常會經過如下代碼將Web Form的引擎刪除:

  

  更多View引擎的內容後續介紹。

ViewEngineCollection&ViewEngine

  在ASP.NET中有一個IViewEngine的接口,它定義了查找和釋放View,其定義以下:

  

  而ASP.NET中實現IViewEngine接口的類型關係以下圖:

  

  從該圖中能夠獲得一下信息:
  ● ASP.NET中有兩個最終實現的ViewEngine,分別是Razor和WebForm,MVC應用中使用Razor實現View的渲染。
  ● 它們的基類都是VirtualPathProviderViewEngine,就是說它們都是基於相對路徑來管理View的。
  ● 它們的基類都是BuildManagerViewEngine,表面它們都和編譯有關(注:在ASP.NET中不管是WebForm仍是MVC,均可以在頁面上編寫代碼,而這些代碼確定是不能被瀏覽器理解的,須要通過編譯纔可以正常工做)。

  ASP.NET中的ViewEngine被一個名爲ViewEngines的集合進行管理,以下圖:

  

  MVC中主要使用的是RazorViewEngine,下圖是RazorViewEngine的部分代碼:

  

  從代碼中能夠看到兩個重要信息,第一是「_ViewStart」被硬編碼爲啓動頁面,這也是爲何在該頁面指定佈局的緣由,另外在其構造方法中硬編碼了各類LocationFormats,它們指定了相應類型頁面的搜索路徑

  那麼上面提到的Razor又是什麼呢?Razor是ASP.NET的一種能夠將服務器代碼嵌入到網頁中的標記語言,它由Razor標記、服務器代碼(C#/VB)以及Html代碼組成。在Html中以@符號開始的內容將會被識別爲服務器代碼,而Razor將識別這些代碼將其渲染爲Html代碼。更多關於Razor的內容可參考:https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor

ViewEngineResult

  ViewEngineResult是ViewEngine對View查找後結果的封裝,其定義以下:

  

  它包含了查找後的結果IView類型以及用於查找的ViewEngine自己,另外還有一個字符串列表用來保存查找該View所遍歷過的路徑。
  下面是RazorViewEngine用來查找和建立RazorView對象的主要代碼,其核心實際就是根據action名稱和Controller名稱與相應的LocationFormats匹配後查找文件是否存在,若是存在則建立IView實例的過程:

  

  而這裏的IView類型就是RazorView:

  

View的編譯與激活

  上面介紹了ViewEngine用來查找並獲取相應IView對象,那IView是用來作什麼的呢?下圖是IView的接口定義,它只有一個Render方法,用來將指定的View上下文信息經過指定的TextWriter進行渲染,這實際上就是將View文件的內容處理後,寫到Http響應數據的過程:

  

  ASP.NET中實現IView的類結構以下:

  

  一樣的有兩種View分別對象Razor和WebForm,而它們的基類都是BuildManagerCompiledView(被BuildManager編譯後的View),並且Render方法也是在基類中實現的,具體代碼以下:

  

  RenderView方法實如今對應的子類中,下圖爲RazorView的RenderView方法:

  

  上面代碼的核心在於:
  1. 經過BuildManager根據View文件的路徑對View文件進行編譯,並得到編譯後的類型(注:BuildManager是ASP.NET中用於對程序集、頁面進行編譯的工具)。
  2. 經過激活器建立View編譯後的類型,下圖是默認使用的激活器,其核心是經過依賴解析器或者Activator來直接建立類型實例。

  

  3. 實例化後的對象是一個WebViewPage類型,經過對WebViewPage初始化後(包含起始頁的查找)調用WebViewPage的ExecutePageHierarchy方法完成渲染。

  注:WebViewPage是Razor對應的頁面類型,WebForm對應的是ViewPage和ViewUserControl。

View的渲染

  上面提到View文件編譯後是一個WebViewPage對象,而View的渲染也是由該對象完成的,那麼WebViewPage是什麼?下圖是WebViewPage的定義:

  

  從中能夠看到一些重要的屬性如Html、Ajax、Url等這些能夠在View裏面使用的,有用來生成Html、Url、Ajax的幫助類型,也有如攜帶了數據用於綁定到View上的Model、TempData、ViewBag、ViewData等類型。
  另外WebViewPage繼承至WebPageBase:

   

  WebPageBase類型裏面定義了RenderBody、RenderSection等方法。
  瞭解了WebPage與WebPageBase以後有沒有感受View文件其實是WebPage的一個子類型,在View中能夠隨意使用和調用WebPage和WebPageBase中的屬性和方法。
  下圖是對Contact.cshtml文件編譯後的代碼:

  

  從代碼中證實了以前的猜測,View文件編譯後確實是WebViewPage的子類型,而該類型中的Execute方法是將Html代碼以字符串的形式進行了拼接,拼接過程當中若是遇到特殊方法的調用則拼接特殊方法的返回值:

  

  

  以上代碼來自佈局文件的編譯結果。
  而Execute方法也就是最終ASP.NET MVC進行View渲染的實際方法。WebViewPage的ExecutePageHierarchy是由於MVC中頁面可能依賴多個View,如默認狀況下頁面有StartPage中指定的佈局View和內容View,爲了保證渲染內容順序不變ExecutePageHierarchy方法中引入了棧機制(後進先出)。

  

  注:BuildManager編譯的View結果默認路徑爲"%WinDir\Microsoft.NET\Framework\ {Version No}\Temporary ASPNET Files"目錄下,以App_Web_開頭的程序集中,程序集的名稱是根據路徑隨機生成的。

使用示例代碼演示View的渲染過程

  下面就用代碼的方式來演示View的查找、編譯、激活以及渲染的全過程:

  

  全量代碼:

複製代碼
 1 using System;
 2 using System.Collections.Generic;
 3 using System.IO;
 4 using System.Linq;
 5 using System.Web;
 6 using System.Web.Compilation;
 7 using System.Web.Mvc;
 8 using System.Web.WebPages;
 9 
10 namespace My_Blog.Controllers
11 {
12     public class ViewRenderController : Controller
13     {
14         // GET: ViewRender
15         public void Index()
16         {
17             var path = "";
18             var viewEngineResult = this.FindView(out path);//查找View
19             Render(viewEngineResult, path);//渲染View
20         }
21 
22         //View的查找,至關於RazorViewEngine
23         private ViewEngineResult FindView(out string path)
24         {
25             var actionName = "Contact";
26             var controllerName = "Home";
27             var viewLocationFormat = @"~/Views/{1}/{0}.cshtml";
28             //根據Controller和Action名稱與地址模板組成View相對路徑
29             path = string.Format(viewLocationFormat, actionName, controllerName);
30             //根據文件路徑建立RazorView和ViewEngineResult
31             var view = new RazorView(this.ControllerContext, path, "", true, null, null);
32             return new ViewEngineResult(view, new RazorViewEngine());
33         }
34 
35         //View的渲染
36         private void Render(ViewEngineResult viewEngineResult,string path)
37         {
38             Type pageType = BuildManager.GetCompiledType(path);//根據對View文件進行編譯
39             var pageInstance = Activator.CreateInstance(pageType);//建立View文件編譯後類型實例
40             var webViewPage = this.InitViewPage(pageInstance, viewEngineResult, path);//對實例中相關屬性進行初始化
41             webViewPage.ExecutePageHierarchy(//完成View的渲染
42                 new WebPageContext(this.HttpContext, null, null),
43                 this.HttpContext.Response.Output, null);//startpage設置爲null,將不會渲染布局頁面
44         }
45 
46         private WebViewPage InitViewPage(object instance, ViewEngineResult viewEngineResult, string path)
47         {
48             WebViewPage webViewPage = instance as WebViewPage;
49 
50             if (webViewPage == null)
51             {
52                 throw new InvalidOperationException("無效");
53             }
54             ViewContext viewContext = new ViewContext(this.ControllerContext,
55                 viewEngineResult.View, 
56                 this.ViewData, 
57                 this.TempData, 
58                 this.HttpContext.Response.Output);
59             webViewPage.VirtualPath = path;
60 
61             webViewPage.ViewContext = viewContext;
62             webViewPage.ViewData = viewContext.ViewData;
63             webViewPage.InitHelpers();
64             return webViewPage;
65         }
66     }
67 }
複製代碼

  上面的代碼要點以下:
  ● FindView方法實際上表明的就是RazorViewEngine,它根據硬編碼的View文件搜索模板結合Controller和Action的名稱得到View文件的全路徑,並建立RazorView和ViewEngineResult對象。
  ● Render則表明了View的編譯、激活以及渲染過程。

   運行結果(因爲沒有佈局頁面,因此相關的樣式和JS都沒有被引入):

  

View的Html Helper與ModelMetadata

  在ASP.NET MVC的View中能夠經過一些Helper類型來生成HTML代碼,下圖爲用戶註冊頁面的View代碼:

   

  從代碼中能夠看到ASP.NET MVC並非徹底使用Html來構成頁面的,中間有一些經過Html屬性(注:Html是WebViewPage類型中的HtmlHelper類型的實例)調用的方法,從方法的名稱來看這些方法分別用於生成如數據驗證信息、Label標籤、文本框以及密碼類型文本框等HTML代碼。
  ASP.NET MVC提供了一系列的Helper類及其拓展方法,這些Helper類中封裝了針對HTML、Ajax(ASP.NET MVC中Ajax Helper的用法可參考:https://www.c-sharpcorner.com/article/Asp-Net-mvc-ajax-helper/)等相關內容的實現,ASP.NET MVC對Html拓展能夠分爲如下四類:
  1. 用於生成特定標籤的拓展,如Form、Input、Label、TextArea、Select等拓展。
  使用方式以下:

  

  將經常使用的HTML標籤進行封裝,對於不熟悉Html的開發人員來講ASP.NET MVC提供了一種面向對象編程的方式來對頁面進行開發,更重要的是Html方法能夠與模型關聯,當模型的元數據中有相應的驗證特性而且開啓了客戶端驗證時,在渲染標籤時會包含相應的驗證信息,使用這類標籤最大的好處就是能夠將關注點所有放在模型上,當模型發生變化時View上不須要作任何的修改。

  2. 用於生成Model驗證信息的拓展。
  使用方式以下:

  

  ASP.NET MVC中提供了模型驗證的機制,當模型驗證失敗時會有相應的失敗信息,而該拓展就是對這些錯誤信息進行渲染,大大的減小了輸出驗證信息的工做量。

  3. 根據用途「展現/編輯」生成標籤的Display以及Editor拓展。
  使用方式以下(注:DisplayFor是用於顯示指定模型屬性中的值,若是要顯示對應模型屬性的名稱可用DisplayNameFor):

  

  Display與Editor是根據模型的數據類型來判斷如何對模型進行展現。ASP.NET MVC中爲Display和Editor提供了一些基礎類型的默認模板實現分別經過內部靜態類型DefaultEditorTemplates和DefaultDisplayTemplates進行存儲,下面是bool類型模板代碼:

  

  

  在提供默認模板的同時ASP.NET MVC也提供了自定義模板的機制,能夠分別使用DisplayAttribute與UIHintAttribute對特定屬性指定渲染模板,如何自定義Display和Editor模板可參考:http://www.growingwiththeweb.com/2012/12/aspnet-mvc-display-and-editor-templates.html

  4. Partial拓展。
  使用方法(注:第一個參數是Partial View的名稱,默認狀況下Partial View文件存儲於Views/Shared目錄下,若是文件不在這個目錄下須要在參數中體現具體目錄):

  

  Partial是ASP.NET MVC中用於將可重用Html進行分離的機制,而且Partial是能夠訪問數據的,就是說經過parital分離的Html代碼,能夠根據傳入的數據來動態生成Html代碼,更多關於Partial View的內容可參考.Net Core的文檔:https://docs.microsoft.com/en-us/aspnet/core/mvc/views/partial

  5. Child Action拓展。
  使用方法:

  

  Child Action相似於Partial View,它也是將可重用的部分進行分離,但Partial View更側重於關注Html代碼重用,Child Action還包含了後端邏輯的重用。如購物網站的購物車,它可能出如今任意的頁面中,但首頁的邏輯、模型與購物車就可能沒有任何關係,此時就可使用Child Action。

經常使用的ActionResult

  前面提到過ASP.NET MVC的頁面渲染工做其實是由一個繼承至ActionResult的ViewResult對象完成的,ActionResult其實是ASP.NET MVC中的一個抽象,表明了全部邏輯執行後的結果,而ViewResult是將結果面向人的,因此返回了Html讓瀏覽器顯示給人看,除了ViewResult以外還有一些經常使用的ActionResult以下:
  ● ContentResult:用於將字符串返回到客戶端,在Action方法中調用Content方法返回。
  ● FileStreamResult:用於將文件返回到客戶端,在Action方法中調用File方法(有多個重載)返回。
  ● HttpNotFoundResult:用於返回HTTP未找到狀態,在Action方法中調用HttpNotFound方法返回。
  ● JavaScriptResult:用於將JavaScript返回到客戶端並執行,在Action方法中調用JavaScript方法返回。
  ● JsonResult:用於將Json數據返回到客戶端,在Action方法中調用Json方法返回。
  ● PartialViewResult:用於渲染partial頁面,在Action方法中調用PartialView方法返回。
  ● RedirectResult:用於重定向,在Action方法中調用Redirect方法傳入須要重定向的Url進行重定向操做。
  ● RedirectToRouteResult:用於路由重定向,在Action方法中調用RedirectToAction方法重定向到指定的Action。
  ● EmptyResult:返回空,在Action方法中返回Null或將Action方法的返回值設爲Void便可。

小結

  本文介紹了ASP.NET MVC如何在Action方法執行時經過對ActionResult(ViewResult)的執行完成View文件的查找、編譯以及渲染的過程,除了ViewResult以外ASP.NET MVC還提供了其它類型的ActionResult如Json、File等,使用這些結果能夠建立簡單的Web API以及文件下載等功能,另外MVC經過Html Helper類型對View進行了拓展,在開發View時能夠最大程度的對View的Html代碼和邏輯進行重用,同時也將View與Model(特指ViewModel)進行關聯,在開發時能夠將關注點放在Model上,無需擔憂Model修改後View代碼的修改。合理的使用View提供的相關機制,能夠極大的減小工做量同時也可讓代碼變得更加簡潔。

參考:
  https://zhuanlan.zhihu.com/p/29418126
  https://www.codeproject.com/Articles/787320/An-Absolute-Beginners-Tutorial-on-HTML-Helpers-and
  https://www.c-sharpcorner.com/article/Asp-Net-mvc-ajax-helper/
  http://www.growingwiththeweb.com/2012/12/aspnet-mvc-display-and-editor-templates.html
  https://stackoverflow.com/questions/5037580/asp-net-mvc-3-partial-vs-display-template-vs-editor-template
  https://weblogs.asp.net/scottgu/introducing-razor
  https://docs.microsoft.com/en-us/aspnet/core/mvc/views/razor

 本文連接:http://www.cnblogs.com/selimsong/p/8670744.html 

ASP.NET沒有魔法——目錄

 

 

ASP.NET沒有魔法——ASP.NET MVC界面美化及使用Bundle完成靜態資源管理

 

  對於一個應用來講界面的重要性無言而喻,而Web應用的界面是使用Html+Css以及Javascript實現的,ASP.NET MVC是一個用來構建Web應用的框架,它的界面也是Html實現的,對於一些開發團隊來講,通常Web項目會存在專業的UI前端工程師和後端工程師,前端工程師可能只懂設計和Html,可是對於如何將設計好的Html應用到ASP.NET可能就須要ASP.NET工程師的幫助。
  本文將介紹如何將已經設計好的Web界面應用到ASP.NET MVC中以及如何對這些資源文件進行管理,先看一下修改後的效果:

  

    

  本章的主要內容有:
  ● 素材選擇
  ● ASP.NET MVC的界面佈局及界面實現
  ● 使用BundleConfig進行素材資源管理
    ○ 使用bundle對素材分類
    ○ 使用Bundle對資源文件進行優化
    ○ 在Bundle中使用通配符及文件版本(min版)的選擇
    ○ 使用CDN
    ○ Bundle中的緩存
    ○ Bundle重寫樣式表中資源引用路徑
    ○ 自定義資源轉變(Transform)
  ● 小結

素材選擇

  本文選取開源主題Start Bootstrap - Clean Blog爲例進行介紹。
  Clean Blog是一個現代風格的響應式主題,基於bootstrap 4.0,下圖爲Clean Blog的運行效果:

  

  將Clean Blog下載到本地並導入《My Blog》項目中,該主題中包含了相應的樣式表、圖片、Js、示例頁面等文件:

  

  注:Clean Bolg的GitHub地址:https://github.com/BlackrockDigital/startbootstrap-clean-blog

ASP.NET MVC的界面佈局及界面實現

  Clean Blog是由Html、Css、Javascript文件組成的一個靜態Web界面,要將其應用到ASP.NET MVC中,只須要對其結構進行分析後一一替換到ASP.NET MVC的View中便可。
因此首先要分析的是Clean Blog以及My Blog應用的頁面佈局,對於Clean Blog來講它分爲三塊,分別是導航、內容以及頁腳:

  

  一樣的My Blog以前使用的ASP.NET MVC默認模板也是分爲了導航、內容和頁腳:

  

  對於上面的佈局來講,導航和頁腳部分是不變的,只有中間的內容是變化的,在ASP.NET MVC中提供了佈局頁的機制,專門用來定義頁面佈局,將不變的內容放置在該佈局頁面上,因此要更換界面首先須要的就是定義佈局頁面:
  在Views/Shared目錄下添加一個新的佈局頁面,將Clean Blog的Index頁面中的導航以及頁腳代碼複製到新的佈局頁面中,包括css以及js的引用(注:須要修改路徑),頁面內容部分使用@RenderBody()方法代替:

  

  同時將_ViewStart.cshtml中指定的佈局文件改成新建立的CleanBlog佈局文件:

  

  最後參照Clean Blog內容頁樣式完成相應內容頁面修改便可,下面以「聯繫咱們」頁面爲例:

  

  運行效果(注:沒有實現原主題中的信息提交功能):

  

  

 

使用BundleConfig進行素材資源管理

  經過上面的介紹知道了如何經過佈局頁面來搭建頁面內容,Web頁面除了自己的Html代碼外還少不了css、JavaScript等文件的支持,但這些文件都是相對零散的,在ASP.NET中有一個Bundle機制專門用於管理這些資源文件。
  Bundle有捆和包的意思,而在ASP.NET MVC中它實際就是能夠將一組css或JavaScript捆綁起來,捆綁能夠根據資源的一些特性進行歸類,與此同時還添加了一些有用的附加功能,如:文件最小化、資源文件的版本管理、使用CDN加速、資源文件的緩存等等,下面就介紹如何使用bundle來管理新添加到項目中的素材資源。

使用bundle對素材分類

  爲了保證頁面樣式一致,因此在建立佈局文件時添加了全站共用的樣式和腳本,Clean Blog是基於Bootstrap4.0創建的,除此以外還有一些特殊的內容,以下圖所示,它的實例代碼中已經進行過度類:

  

  樣式主要包括Bootstrap的核心樣式、模板中使用的字體以及模板中的自定義樣式,一樣JavaScript除了bootstrap必要的JavaScript外還有自定義的JavaScript。根據這個分類規則,在App_Start/BundleConfig的BundleConfig類型中註冊分類:

  樣式分類:

  

  腳本分類:

  

  注:建議bundle的地址以bundles做爲前綴,避免與路由衝突。
  完成後在佈局文件中改用Bundle渲染樣式和腳本:

  

使用Bundle對資源文件進行優化

  前面經過Bundle對資源進行了分類,當同一類資源下存在多個文件時,頁面只須要一句代碼就能夠所有引入使代碼更清晰,固然Bundle機制在資源分類的同時,更重要的是能夠對資源文件進行優。
  這裏的優化有兩個點分別是文件請求的優化和文件大小的優化,前者是將同一類的文件進行合併,合併成一個文件,在請求時只需請求一次便可,後者是將css及JavaScript中不須要的字符刪除、變量名稱簡寫以達到縮減文件尺寸的目的。
  使用Bundle管理資源時,在Release模式下將自動進行優化,另外也能夠設置BundleTable.EnableOptimizations爲true進行強制優化,以下圖所示:

   

  運行時將能夠看到以下結果:
  1. 請求數量減小:

  

  2.非最小化的js文件被最小化,如clean-blog.js:

  

  注:上面請求中出現字體文件沒法找到的錯誤將在後續內容解釋。

在Bundle中使用通配符及文件版本(min版)的選擇

  對於一些樣式或腳本組件來講,它自己就可能由多個文件構成,以下圖中的Jquery目錄中就有jquery.js以及jquery.slim.js兩個文件:

  

  在一些複雜的應用中還可能會使用到jQuery的其它組件,這樣資源文件會更多,爲了簡化Bundle對資源的歸類,在使用Bundle註冊分類時,可使用通配符來一次匹配多個文件:

    

  注:Bundle中能識別的通配符有兩種,經常使用的就是「*」,另外還能夠經過「{version}」來匹配文件版本。更多通配符相關內容可參考:https://docs.microsoft.com/en-us/aspnet/mvc/overview/performance/bundling-and-minification#using-the--wildcard-character-to-select-files
  直接使用*通配符能夠匹配相應目錄下的全部文件,下圖是運行結果:

  

  從圖中能夠看到,比以前的請求中多了一些js文件,這些文件就是經過通配符匹配到的,但要注意的是這裏沒有獲取包含.min版本的js文件,在相同目錄下clean-blog.js以及jquery.js都有被最小化的min版本:

  

  Bundle機制會根據debug/release模式或者BundleTable.EnableOptimizations屬性來判斷是否對資源文件優化,在release模式(web.config中compilation的debug屬性爲true)下或者BundleTable.EnableOptimizations設爲true時會啓用資源優化,這裏的資源優化除了上面提到的多個文件捆綁外,若是文件列表中有min版本文件,那麼就會優先選擇min版本文件。
  因爲優化模式下沒法看到具體請求的文件名稱,因此在clean-blog.min.js中添加一條日誌輸出代碼:

  

  而後使用release模式運行程序,將會得到下面結果:

  

  除了看到請求減小之外,還看到日誌中輸出了min版本文件中添加的內容,證實使用release模式運行時Bundle會自動選擇文件最小化的版本。

使用CDN

  CDN(內容分發網絡),爲了提升web的響應速度,其中一項主要的優化手段就是將靜態資源放到CDN上,這樣用戶就能夠在離他最近的網絡節點獲取到這些資源,這樣既提升了資源獲取的速度同時也下降了應用服務器的壓力,ASP.NET中的Bundle能夠爲相應的資源配置CDN,而且該配置也是release模式下生效:

  

  使用CDN主要有如下幾個步驟:
  ● 將bundles的UseCdn屬性設爲true。
  ● 建立Bundle對象時構造方法中傳入CDN的路徑。
  ● 設置Bundle對象的CdnFallbackExpression屬性,該屬性用於判斷經過CDN加載的內容是否正確加載,若是沒有那麼會加載Include中的內容。

  運行效果:

  

  將bundles.CdnFallbackExpression的屬性設置爲window.jQuery會生成一個判斷window.jQuery對象是否存在,若是不存在則獲取服務器資源的代碼:

  

  經過修改CDN資源路徑,模擬CDN沒法訪問狀況,它會自動加載可用的資源:

  

  CDN可用資源參考:http://www.bootcdn.cn/

Bundle中的緩存

  在Release或資源優化模式下,Bundle爲其管理的資源提供了緩存機制,在第一次訪問Bundle管理的資源時,Bundle會爲每一組資源生成一個惟一標識,而後將該資源默認緩存一年:

  

  當資源發生改變時惟一標識會發生變化,那麼原來緩存的內容就自動失效了。

Bundle重寫樣式表中資源引用路徑

  在前面的介紹的過程當中release模式下一直有一個錯誤,就是沒法找到字體文件,這是由於在編寫樣式時會引入一些字體或者圖片等外部資源,而這些資源通常是用相對路徑進行引用的,可是當ASP.NET中使用Bundle來對樣式資源進行捆綁時,該資源的url地址就發生改變了,致使使用該地址組合的引用資源的地址不正確,從而致使了資源沒法加載:

  

  爲了解決這一問題,Bundle提供了一個重寫樣式引用相對路徑的解決方案,在將樣式表註冊到Bundle中時,能夠爲相應的樣式文件添加一個CssRewriteUrlTransform對象,它用於Css文件優化時對其引用的Url進行重寫:

  

  添加以上代碼後,運行程序將解決字體沒法找到的問題:

  

自定義資源轉變(Transform)

  資源轉變是Bundle機制在優化資源時提供的一個可拓展接口,如上面介紹的css Url重寫就是資源轉變的拓展,Bundle中實現資源轉變須要實現如下接口:

   

  接口中的參數分別表明獲取到文件的虛擬路徑和文件的內容。
  下面建立一個在css中插入自定義內容的資源轉換器,來介紹如何實現資源轉變的自定義拓展:
  實現IItemTransform接口,在樣式文件中追加".test {color: red;}"樣式:

  

  將該轉換器經過Include方法應用到對應文件上:

  

  運行結果顯示相應內容已經被添加到最終的樣式文件中:

  

  注:IItemTransform接口是在資源優化前調用的,因此本例添加內容包含的空格和分號最終都被優化刪除了,因此在使用IItemTransform進行拓展時須要注意資源優化問題。
  另外在Bundle中還有另一個拓展接口IBundleTransform,它定義了一個用於轉換Bundle相應文件的方法:

  

  實現Process接口,在響應的內容上添加註釋「hello selim」:

  

  BundleTransform須要在Bundle的Transforms屬性上添加:

  

  運行結果:

  

  相對與ItemTransform來講BundleTransform處理後的內容不會再進行優化,在文檔https://docs.microsoft.com/en-us/aspnet/mvc/overview/performance/bundling-and-minification#less-coffeescript-scss-sass-bundling中還經過BundleTransform實現了less等文件動態編譯的功能,有興趣可參考該文檔。

小結

  本章主要介紹瞭如何將現有的Web樣式應用到ASP.NET MVC中,並着重介紹了ASP.NET MVC中對靜態資源管理的Bundle機制。Bundle機制除了能夠對資源文件進行歸類外還提供了資源文件優化、CDN、緩存等高級功能。合理的利用Bundle可讓項目代碼更清晰,同時也能夠提升應用的性能。

參考:
  https://github.com/BlackrockDigital/startbootstrap-clean-blog
  https://html.com/attributes/
  https://docs.microsoft.com/en-us/aspnet/mvc/overview/performance/bundling-and-minification
  https://www.codeproject.com/articles/842961/introducing-dynamic-bundles-for-asp-net-mvc
  https://stackoverflow.com/questions/11355935/mvc4-stylebundle-not-resolving-images#
  http://www.bootcdn.cn/
  http://www.tutorialsteacher.com/mvc/scriptbundle-mvc
  https://www.codeproject.com/Articles/728146/ASP-NET-MVC-bundles-internals
  https://blogs.msdn.microsoft.com/rickandy/2011/05/21/using-cdns-and-expires-to-improve-web-site-performance/

本文連接:http://www.cnblogs.com/selimsong/p/8589175.html 

 ASP.NET沒有魔法——目錄

相關文章
相關標籤/搜索