ASP.NET MVC Razor介绍:RazorViewEngine
基于Web Form引擎的WebFormViewEngine和针对Razor引擎的RazorViewEngine都是抽象类型BuildManagerViewEngine的子类,而后者又继承自VirtualPathProviderViewEngine。 在这里我们仅仅对实现在RazorViewEngine中View获取的逻辑进行简单介绍。由于Razor引擎下的View通过RazorView对象来 表示,而RazorView通过View文件的虚拟路径来构建,所以RazorViewEngine的View获取机制在于根据当前上下文找到与指定 View名称相匹配的View文件(.cshtml或者.vbhtml文件),然后根据该 View文件的虚拟路径创建一个RazorView对象并最终封装成ViewEngineResult对象返回。
实现在RazorViewEngine中的目标View文件的搜索是根据一个预定义顺序进行的。如果当前请求不是针对某个Area的,下面的列表代表了View的搜索顺序:
- ~/Views/{ControllerName}/{ViewName}.cshtml
- ~/Views/{ControllerName}/{ViewName}.vbhtml
- ~/Views/Shared/{ViewName}.cshtml
- ~/Views/Shared/{ViewName}.vbhtml
对于针对某个Area的请求,RazorViewEngine会先按照如下的顺序对目标View进行搜索。如果在这个列表中没有成功找到目标View文件,会继续按照上面的属性进行搜索。
- ~/Areas/{AreaName}/Views/{ControllerName}/{ViewName}.cshtml
- ~/Areas/{AreaName}/Views/{ControllerName}/{ViewName}.vbhtml
- ~/Areas/{AreaName}/Views/ Shared /{ViewName}.cshtml
- ~/Areas/{AreaName}/Views/ Shared /{ViewName}.vbhtml
如果按照上面的搜索顺序依然找不目标View文件,RazorViewEngine会根据这个列表创建并返回一个ViewEngineResult对象。这里介绍的View搜索机制不仅仅应用于普通的View文件,还应用于Partial View和布局文件的搜索。
ViewEngine 不仅仅通过FindView/FindPartialView根据当前上下文获取指定的View,还通过ReleaseView对指定的View进行释放 回收操作。ReleaseView方法在RazorViewEngine的实现很简单,如果指定的View对象的类型实现IDispose接口,它会直接 调用其Dispose方法。下图所示的UML体现了Razor引擎涉及的相关类型/接口以及它们之间的相互关系。
在《ASP.NET MVC Razor介绍:RazorView》一文中我们创建了一个用于模拟RazorView的SimpleRazorView,现在我们为它创建一个对应的RazorViewEngine,我们直接在该实例项目中添加如下一个SimpleRazorViewEngine。
public class SimpleRazorViewEngine: IViewEngine
{
private string[] viewLocationFormats = new string[] {
"~/Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.vbhtml",
"~/Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.vbhtml" };
private string[] areaViewLocationFormats = new string[] {
"~/Areas/{2}/Views/{1}/{0}.cshtml",
"~/Areas/{2}/Views/{1}/{0}.vbhtml",
"~/Areas/{2}/Views/Shared/{0}.cshtml",
"~/Areas/{2}/Views/Shared/{0}.vbhtml" };
public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
{
return FindView(controllerContext, partialViewName, null, useCache);
}
public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
string controllerName = controllerContext.RouteData.GetRequiredString("controller");
object areaName;
List<string> viewLocations = new List<string>();
Array.ForEach(viewLocationFormats, format => viewLocations.Add(string.Format(format, viewName, controllerName)));
if (controllerContext.RouteData.Values.TryGetValue("area", out areaName))
{
Array.ForEach(areaViewLocationFormats, format=>viewLocations.Add(string.Format(format,viewName,controllerName, areaName)));
}
foreach (string viewLocation in viewLocations)
{
string filePath = controllerContext.HttpContext.Request.MapPath(viewLocation);
if (File.Exists(filePath))
{
return new ViewEngineResult(new SimpleRazorView(viewLocation),
this);
}
}
return new ViewEngineResult(viewLocations);
}
public void ReleaseView(ControllerContext controllerContext, IView view)
{
IDisposable disposable = view as IDisposable;
if (null != disposable)
{
disposable.Dispose();
}
}
}
我们完全按照上面介绍的路径顺序搜索指定的目标View。简单起见,我们在对目标View进行搜索时忽略了指定的布局文件名和对 ViewEngineResult的缓存。这个自定义的SimpleRazorViewEngine在Global.asax中通过如下的代码对进行注册。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
//其他操作
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new SimpleRazorViewEngine());
}
}
我们定义了如下一个HomeController:
public class HomeController : Controller
{
public ActionResult Index()
{
Contact contact = new Contact
{
Name = "张三",
PhoneNo = "123456789",
EmailAddress = "zhangsan@gmail.com"
};
return View(contact);
}
}
public class Contact
{
[DisplayName("姓名")]
public string Name { get; set; }
[DisplayName("电话号码")]
public string PhoneNo { get; set; }
[DisplayName("电子邮箱地址")]
public string EmailAddress { get; set; }
}
我们的View(“~/Views/Home/Index.cshtml”)很简单。如下面的代码片断所示,这是一个Model类型为 Contact的强类型View,在该View中我们直接调用HtmlHelper<TModel>的扩展方法EditorForModel 将作为Model的Contact对象以编辑模式呈现在一个表单之中。
@model Contact
@{
ViewBag.Title = Model.Name;
}
@using (Html.BeginForm())
{
@Html.EditorForModel()
<input type="submit" value="保存" />
}
为了验证我们自定义的SimpleRazorView对布局文件和_ViewStart页面的支持,我们在“~/Views/Shared/”目录 下定义了如下一个名为“_Layout.cshtml”的布局文件。布局文件的设置通过定义在“~/Views/”目录下具有如下定义的 “_ViewStart.cshtml”文件来指定。
_Layout.cshtml:
<html>
<head>
<title>@ViewBag.Title </title>
</head>
<body>
<h3>编辑联系人信息</h3>
@RenderBody()
</body>
</html>
_ViewStart.cshtml:
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
运行我们的程序后会在浏览器中呈现如下图所示的输出结果,可以看出这和我们直接在Action方法Index中返回一个ViewResult对象没有什么不同。
作者:Artech
出处:http://artech.cnblogs.com/
加支付宝好友偷能量挖...



