根據ScottGu的部落格記述(http://weblogs.asp.net/scottgu/archive/2010/07/02/introducing-razor.aspx),在未來不久將會發布一個ASP.NET MVC 3.0的Preview版本,在這個版本中可以使用多個內建的模板引擎,以它發布出來的來看,其中包括NHaml,Spark以及微軟剛剛發布的ASP.NET Web Pages(Razor)。 ASP.NET Web Pages包含在Web Matrix中,提供了一種新的模板模式,其副檔名為 .vbhtml/.cshtml,可以使用類似以下文法來做視圖顯示:
@{var i = 11;}@(i+1)<br>@if (i%2==1){<p>true</p>}else{<p>false</p>}
輸出結果為:
12<br> <p>true</p>
在不久之後Ms還會對此提供Visual Studio 高亮及智能感知支援。
這種模板如此簡捷,如果能用在現有的ASP.NET MVC 2.0上做為一個模板引擎是不錯的。
首先我們要安裝ASP.NET Web Pages,:http://bbs.eice.com.cn/showtopic-409.aspx ,當然直接安裝WebMatrix也是可以。
安裝之後在IIS中就會添加對cshtml及vbhtml的支援。
安裝後組件檔會被複製到Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies目錄下。
其中包括
Microsoft.Data.dllMicrosoft.Web.Infrastructure.dllMicrosoft.Webpages.Compilation.dllMicrosoft.Webpages.Configuration.dllMicrosoft.Webpages.dllMicrosoft.Webpages.Helpers.dllMicrosoft.Webpages.Helpers.Toolkit.dll
下面我們就動手對ASP.NET MVC程式添加一個Razor的模板引擎:
首先建立一個ASP.NET MVC的項目,然後對其中的Web.Config的system.web/compilation/assemblies節點上新增內容:
<add assembly="Microsoft.WebPages.Compilation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/><add assembly="Microsoft.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/><add assembly="Microsoft.WebPages.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/><add assembly="Microsoft.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
並對system.web/compilation/buildProviders新增內容:
<add extension=".cshtml" type="Microsoft.WebPages.Compilation.InlinePageBuildProvider" />
並引用相應的
Microsoft.Data.dll Microsoft.Webpages.dll Microsoft.Webpages.Helpers.dll Microsoft.Webpages.Compilation.dll
幾個檔案
準備工作做好了,下面就來實現相應的模板引擎,我們先來實現一個IView對象:
public class WebPageView : IView { public WebPageView(string viewPath) : this(viewPath, null) { } public WebPageView(string viewPath, string masterPath) { if (string.IsNullOrEmpty(viewPath)) { throw new ArgumentException("viewPath can't null", "viewPath"); } this.ViewPath = viewPath; this.MasterPath = masterPath ?? string.Empty; } public virtual void Render(ViewContext viewContext, TextWriter writer) { if (viewContext == null) { throw new ArgumentNullException("viewContext"); } WebPage page = WebPage.CreateInstanceFromVirtualPath(this.ViewPath);//load cshtml file if (page == null) { throw new InvalidOperationException("cshtml file not exists"); } else { this.RenderViewPage(viewContext, page); } } private void RenderViewPage(ViewContext context, WebPage page) { if (!string.IsNullOrEmpty(this.MasterPath)) { page.LayoutPage = this.MasterPath; } page.VirtualPath = this.ViewPath; page.ExecutePageHierarchy(CreatePageContext(context) , context.HttpContext.Response.Output, null); //execute cshtml file } internal static WebPageContext CreatePageContext(ViewContext content) { var pc = new WebPageContext(); var t = pc.GetType(); t.InvokeMember("HttpContext", BindingFlags.SetProperty | BindingFlags.NonPublic | BindingFlags.Instance , null, pc, new[] { content.HttpContext }); t.InvokeMember("ViewContext", BindingFlags.SetProperty | BindingFlags.NonPublic | BindingFlags.Instance , null, pc, new[] { content }); return pc; } /// <summary>Gets or sets the master path.</summary> /// <returns>The master path.</returns> public string MasterPath { get; private set; } /// <summary>Gets or sets the view path.</summary> /// <returns>The view path.</returns> public string ViewPath { get; private set; } }
然後我們再來實現一個IViewEngine對象:
/// <summary> /// WebPage View Engine /// </summary> class WebPageEngine : VirtualPathProviderViewEngine { public WebPageEngine() { // how to find the template path base.MasterLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" }; base.AreaMasterLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml" }; base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/Shared/{0}.cshtml" }; base.AreaViewLocationFormats = new string[] { "~/Areas/{2}/Views/{1}/{0}.cshtml", "~/Areas/{2}/Views/Shared/{0}.cshtml" }; base.PartialViewLocationFormats = base.ViewLocationFormats; base.AreaPartialViewLocationFormats = base.AreaViewLocationFormats; } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { return new WebPageView(partialPath, null); } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { return new WebPageView(viewPath, masterPath); } }
這樣我們就實現了Razor的模板引擎了,我們只要在Global.asax中將模板引擎添加進去:
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterRoutes(RouteTable.Routes); ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new WebPageEngine()); }
並且將Global的基類改為WebPageHttpApplication:
public class MvcApplication : WebPageHttpApplication{//...}
這樣整個程式就可以工作了
我們在Views/Home下添加一個Index.cshtml:
@Html.ActionLink("Home","index","User")<br>@ViewData["Message"]
這樣在我們訪問/Home/Index的時候就可以得到ASP.NET MVC預設工程的HomeController.Index所產生的頁面了:
<a href="/User">Home</a>
<br>
歡迎使用 ASP.NET MVC!
可見在這個模板引擎中,先天對ASP.NET MVC有良好的支援,本身已經整合了Helper、ViewData等諸多ASP.NET MVC的特性。
讓我們期待ASP.NET MVC 3.0及Razor對VS的支援吧
8189E6B8-FBE4-4F01-8F9F-5687C0EA9F59