以往開發ASP.NET Web Form時,在ASPX頁面上都會出現許多夾雜C#/VB.NET與HTML的狀況,而先前使用<%...%>這種傳統圓角括號的表示法會讓HTML標籤與ASP.NET代碼區塊混雜一塊兒,當頁面變得複雜後,這類混合的代碼也開始變得難以閱讀,相信你們都有相同的感覺。html
從ASP.NET MVC3開始引入了全新的Razor語法,用@符號來表明代碼段,試圖提供一個容易學習又精簡的語法。Razor語法推出以後,廣受ASP.NET MVC開發人員的喜好,搭配Visual Studio開發工具的語法高亮顯示下,Razor語法也讓整份View頁面內的HTML標籤與服務器代碼結合得很是漂亮,再也不有吃意大利麪的感受了。web
咱們先來回顧以往ASP.NET Web Form在ASPX頁面上輸出當前時間的表示法:瀏覽器
<%: DateTime.Now %>
若使用Razor語法,將會變成如下撰寫風格安全
@DateTime.Now
Razor並非一個代碼語言,它只是一種用在View頁面的代碼區塊撰寫風格罷了,所寫的代碼同樣是C#或VB.NET,所以開人員並不用額外學習過多的語言就能快速上手。
若要使用C#語言來編寫Razor頁面,View頁面的擴展名必須使用cshtml才行。同理VB.NET語言,要用vbhtml。服務器
1.Razor基本語法架構
在頁面中輸出單一變量時,只要在C#語句以前加上@符號便可。mvc
<p> 如今時刻:@DateTime.Now </p>
請注意,上述範例中雖然使用C#語言編寫代碼,但輸出單一變量時不須要加上分號結尾。在頁面中輸出一段含有表達式的結果時,必須在先後加上一個小括號。app
<p> 會員名稱:@(User.Identity.Name+Model.MemberLevel) 啓用狀態:@(ViewBag.IsEnabled?"啓用":"停用") </p>
在頁面中執行多行C#代碼時,必須在先後加上個大括號。框架
@{ var name="Will"; var message="你好,我是 "+name; }
請注意,上述範例中因爲@{到}之間屬於一個C#代碼區段,在撰寫代碼時必須符合C#語言規範,也就是每句話都要有分號結尾。
若是要在多行C#代碼的Razor語法中插入HTML或其餘文字內容,必須在每一行最前面加上一個「@:」符號,並且加上「@:」符號的這行代碼裏,也能夠再加上其餘Razor變量。asp.net
@{ var name="Will"; @:你好,我是@name }
若是要在Razor視圖頁面中標識服務器端註釋,可使用「@*」與「*@」來當註解的頭尾。
@*<hgroup class="title"> <h1>@ViewBag.Title.</h1> <h2>@ViewBag.Message</h2> </hgroup>*@
若是要在Razor視圖頁面中輸出"@"符號。
@@Will_Huang
上述Razor語法最後會輸出「@Will_Huang」。
2.Razor與HTML混合輸出
在View視圖裏混合使用HTML標籤與Razor語法,在許多狀況下能夠用得很是順利,但若是不瞭解Razor的判斷邏輯,也可能會讓你在開發的過程當中不斷受挫,如今就來介紹幾個經常使用的混合編寫風格。
在頁面中編寫if判斷句,其範例以下:
@if (ViewBag.IsEnabled){ @:啓用 } else { @:停用 }
若是要在代碼區塊中輸出大量文字,只要在代碼區塊裏的先後加上一組HTML標籤便可,Razor會只能地判斷出這不是一段C#語法,而是一段HTML標籤文字,如此一來,就不用在每一行前面加上「@:」符號了,以下所示。
@if (ViewBag.IsEnabled) { <span>啓用</span> } else { <span>停用</span> }
VS2012提供Razor語法的高亮顯示,只要是Razor可被識別的C#代碼,都會在背景加上一個淡淡的藍色,若是是白底色的話,那就表明是Razor之外的純文字。
若是咱們在這個區段中徹底不想輸出任何先後的標籤該怎麼辦呢?在Razor頁面裏,可使用特殊的<text>標籤來代替這個HTML標籤,最後輸出到瀏覽器時不會輸出<text>這個標籤,以下所示。
@if (ViewBag.IsEnabled) { <text> 顯示啓用的HTML段落: <p> @ViewBag.EnabledMessage </p> </text> } else { <text> 顯示停用的HTML段落: <p> @ViewBag.DisabledMessage </p> </text> }
3.Razor與HTML混合輸出陷阱與技巧
(1)屬性名稱誤判
有時候咱們必須讓HTML內容與Razor語句牢牢黏在一塊兒。顯示效果爲,「您好,Will先生」,其中Will爲一個變量ViewBag.Name。若是輸入如下Razor語法:
您好,@ViewBag.Name先生
這句話中,Razor會把「@ViewBag.Name先生」當成一個C#語法,修改以下:
您好,@(ViewBag.Name)先生
另外一種解決方法就是多用一個HTML標籤包起來,以下:
您好,<span>@ViewBag.Name</span>先生
或修改以下:
您好,@ViewBag.Name<span>先生</span>
(2)未預期的額外屬性
要輸出以下。
類別是System.Web.Mvc.Controller
若是按如下輸出,會出錯。
@{ ViewBag.MvcNamespace="System.Web.Mvc"; } 類別是@ViewBag.MvcNamespace.Controller
如何修改?
類別是@(ViewBag.MvcNamespace).Controller
(3)輸出Email地址與@轉義符
若是咱們要在Razor頁面中輸出Email超連接,輸出的結果多是這樣:
<a href="mailto:teacher@example.com">teacher@example.com</a>
這裏並不須要改爲@@,由於Razor會自動判斷先後文,只要"@"的前面與後面都有文字的狀況下,@就會停用Razor語法解析,因此在Razor裏輸入Email是徹底不用編寫「@」轉義字符。
若是要輸出的HTML格式以下:
<a id="LinkBlog01" href="http://blog.miniasp.com">The will will web</a>
要將Blog01替換成Razor變量,那又應該如何輸入呢?
@{ ViewBag.BlogID="Blog01"; } <a id="Link@View.BlogID" href="http://blog.miniasp.com">The will will web</a>
以上代碼將不會被正常解析。解決方法能夠加上小括號。
<a id="Link@(View.BlogID)" href="http://blog.miniasp.com">The will will web</a>
(4)輸出未經HtmlEncode的字符串
預設使用Razor語法輸出變量,全部內容預設都會被HTML編碼(HtmlEncode),這是爲了保護網頁不致遭受跨網站腳本攻擊(Cross-Site Scripting, XSS),有了這個預設值,能保證新手開發人員不寫出不安全的代碼。
@{ ViewBag.Description="<span style='font-weight:bold;'>描述文字</span>"; } @ViewBag.Description
最後輸出的結果會是HtmlEncode過的版本以下:
<span style='font-weight:bold;'>這是描述文字</span>
若是咱們要強迫字符串原封不動地輸出,能夠利用@Html.Raw輔助方法幫助咱們輸出內容,咱們能夠修改上述Razor代碼,代碼以下:
@{ ViewBag.Description="<span style='font-weight:bold;'>這是描述文字</span>"; } @Html.Raw(ViewBag.Description)
最後的輸出以下:
這是描述文字
4.Razor的母版頁面框架
傳統的ASP.NET從2.0版開始推出了MasterPage母版頁面框架,讓你在ASP.NET Web Form頁面能夠經過MasterPage組織出全站一致的外觀與界面。而ASP.NET MVC 1.0/2.0也沿用MasterPage架構組織View頁面的HTML版面架構,不過,ASP.NET MVC 3.0推出的RazorView內建的母版頁面語法與本來的WebFormView的MasterPage相差甚遠,所以,你能夠把Razor母版頁面當成是一個全新的架構來學習,只是母版頁面子觀念上是差很少的。
(1)Razor頁面執行順序
當Controller回傳ViewResult給MvcHandler以後,MvcHandler會先設法找出對應的視圖頁面,當找到適當的Razor頁面後,就會進入Razor頁面執行生命週期,在Razor頁面的執行過程當中有個固定的執行順序。
被MvcHandler找到的Razor頁面會優先執行,執行完畢後,會檢查這個View頁面是否含有母版頁面所需的Layout屬性,若是有的話便試圖載入Layout屬性指定的Razor母版頁面,找到母版頁面以後會開始將內容響應給用戶端。
咱們先以傳統ASP.NET Web Form的MasterPage做爲例子,當MasterPage執行的時候,會先找出ContentPlaceHolder控制項,並將以前母版頁面的執行結果填入後輸出到用戶端。以下所示:
<asp:ContentPlaceHoder ID="MainContent" runat="server" />
實際上在溝通的時候,會把這種在MasterPage定義一個區塊的動做戲稱爲「挖洞」,也就是在MasterPage裏挖了一個洞,而後由主要頁面的內容填入。
在Razor裏,當母版頁面被載入後,執行的過程也同樣,在Razor母版頁面裏也會定義出一些須要被填入的內容(挖洞),而後讓主要頁面的內容填入。
(2)關於_ViewStart文件
/Views/_ViewStart.cshtml文件會在/Views/目錄下任何View被載入前就先被載入,也就是View視圖頁面在執行以前,必定會先來這裏尋找有沒有/Views/_ViewStart.cshtml這個文件,只要有這個文件就會先載入執行。
接着再來看看這個預設文件的內容,此文件只包含了一行指定Layout屬性的代碼,所表明的的意義是:全部/Views/目錄下的View預設都要以~/Views/Shared/_Layout.cshtml爲母版頁面。
這個_ViewStart.cshtml文件不只能出如今/Views/目錄下,任何與Controller同名的Views子目錄下也都能出現相同的_ViewStart.cshtml文件,如此一來,就可讓不一樣的Controller預設載入不一樣的母版頁面。
(3)關於_Layout母版頁面
/Views/Shared/_Layout.cshtml文件,有兩個Razor語法,分別是@RenderBody與@RenderSection這兩段聲明,而這就是所謂的「挖洞宣言」,以下所示。
</header> <div id="body"> @RenderSection("featured", required: false) <section class="content-wrapper main-content clear-fix"> @RenderBody() </section> </div>
@RenderBody()在Razor母版頁面中能夠視爲「預設坑洞」,也就是主要的View頁面在沒有特別聲明的狀況下,全部內容都會被填入到@RenderBody()這個位置。
@RenderSection在Razor母版頁面中能夠被視爲「具名坑洞」,如下語法爲例,咱們在母版頁面中定義了一個名爲featured的坑洞,第二個required具名參數則是聲明這個坑洞是否必須被填滿,若是你在母版頁面設定的「具名坑洞」把required參數指定爲true的話,那麼全部載入這個母版頁面的View頁面都必須輸出相對應的內容,不然就會發生異常情況。
@RenderSection("featured", required:false)
在Index.cshtml頁面,可使用一個特殊的Razor語法,名爲@section,且在後面必須接上一個「坑洞名稱」,好比featured,而在這個@section featured聲明裏,對Razor來講這就是一個代碼區塊,所套用的Razor規則也都同樣。
@{ ViewBag.Title = "Home Page"; } @section featured { <section class="featured"> <div class="content-wrapper"> <hgroup class="title"> <h1>@ViewBag.Title.</h1> <h2>@ViewBag.Message</h2> </hgroup> <p> To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>. The page features <mark>videos, tutorials, and samples</mark> to help you get the most from ASP.NET MVC. If you have any questions about ASP.NET MVC visit <a href="http://forums.asp.net/1146.aspx/1?MVC" title="ASP.NET MVC Forum">our forums</a>. </p> </div> </section> }
5.@helper輔助方法
Razor提供了一種很方便的語法,讓你能夠將View頁面中部份內容或部分代碼抽取出來,變成一個獨立的輔助方法。
@helper ShowUnitPrice(int price) { if(price==0) { @:免費 }else{ @price } }
@foreach(var item in Model) { <tr> <td> @item.Name </td> <td> @item.Description </td> <td> @ShowUnitPrice(item.UnitPrice) </td> </tr> }
其實聲明@helper輔助方法的語法與在C#中聲明方法的方式很是像,惟一的差異就在於不用回傳任何類型,預設就是網頁輸出,十分方便。你能夠把這種編寫風格當成是Razor版的代碼片斷。
若是要將這個@heper輔助方法用在多個不一樣的View頁面裏,你能夠考慮將@helper輔助方法獨立出來,放置在項目根目錄App_Code下,放置在新建的MVC4佈局頁(Razor)UIHelper.cshtml中。以下所示。
最後再改寫本來循環內的@ShowUnitPrice方法,代碼以下:
6.@functions自定義函數
@helper輔助方法的確能夠很方便地完成輔助方法開發,不過卻失去了一些彈性,例如,沒法在@helper輔助方法中自定義屬性(Property),只能單純地傳入參數,而後格式化成你想要呈現的樣子後直接輸出。所以,Razor還提供了@functions自定義函數功能,可以讓你用接近C#類的方式進一步定義更復雜的輔助方法。
@functions{ public IHtmlString GetYesterday() { var theDay = DateTime.Now.AddDays(-1); return new HtmlString(theDay.ToShortDateString()); } }
在與@functions同一頁裏,就能使用上述定義的@GetYesterday()方法來執行。與@helper輔助方法相同,若是但願在多個不一樣的View頁面裏都能使用這個由@functions定義的方法,你也能夠將這段@functions聲明移到項目根目錄的App_Code目錄下的其中一個cshtml文件裏。不過,在搬移@functions代碼聲明時有一個小地方須要注意,就是必需要聲明方法爲靜態(static)才能讓各頁面取用,以下。
@functions{ public static IHtmlString GetYesterday() { var theDay = DateTime.Now.AddDays(-1); return new HtmlString(theDay.ToShortDateString()); } }
7.@model引用模型類型
在Razor頁面裏能夠在頁面最上方經過@model語法設定一組View頁面的強類型數據模型參考,套用了數據模型後,在這個View頁面裏就能夠用具備類型的方式取用Model。
@model IEnumberable<MvcApplication6.Models.Product>
請注意@model語法的第一個字母是小寫m,千萬不要和Model搞混了。
8.@using引用命名空間
在Razor頁面裏能夠在頁面最上方經過@using引用這一個View頁面裏會用到的命名空間,以簡化程序的長度。
@using MvcApplication6.Models @model IEnumberable<Product>
在ASP.NET MVC項目的Views\web.config配置文件中,有個<system.web.webPages.razor>區段設定,底下有個<namespace>區段設定了全部View頁面都會引入的命名空間,若是大部分視圖頁面都要引用相同命名空間的話,能夠在這裏設定載入,如此一來,就不用在每頁最上方加上@using語法了,以下所示。
<pages pageBaseType="System.Web.Mvc.WebViewPage"> <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Optimization"/> <add namespace="System.Web.Routing" /> <add namespace="MvcApplication6.Models"/> </namespaces> </pages>