ASP.NET MVC之视图引擎
ActionResult做了什么?
讲到视图引擎,不得不说ActionResult,因为在Controller中,我们看不到一点视图引擎的影子,唯一提供线索的只有ActionResult,所以我们必须先从AcionResult下手。
下面是ASP.NET MVC提供的所有的ActionResult类型的类图:
这其中用的最多的是ViewResult,ActionResult有一个抽象方法ExecuteResult,这个方法会向用户的请求中写入要输出的内容,比如Response.Write等操作。
最具代表性的ViewResult
在ASP.NET MVC中,ViewResult用的最多,Controller有一个View方法,它来实例化一个ViewResult对象,并返回。下面是View方法:
protected internal virtual ViewResult View(string viewName, string masterName, object model) {
if (model != null) {
ViewData.Model = model;
}
return new ViewResult {
ViewName = viewName,
MasterName = masterName,
ViewData = ViewData,
TempData = TempData
};
}
它实例化一个ViewResult对象,并对其ViewData、TempData赋值,以完成从Controller向页面的传值。ViewResult继承自ViewResultBase,ViewResult有一个IView类型的View属性,IView接口只有一个方法:
public interface IView {
void Render(ViewContext viewContext, TextWriter writer);
}
因此,我们推测IView用于输出内容给用户。ViewResult类的ExecuteResult方法证明了这一点:
public override void ExecuteResult(ControllerContext context) {
if (context == null) {
throw new ArgumentNullException("context");
}
if (String.IsNullOrEmpty(ViewName)) {
ViewName = context.RouteData.GetRequiredString("action");
}
ViewEngineResult result = null;
if (View == null) {
result = FindView(context);
View = result.View;
}
ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
View.Render(viewContext, context.HttpContext.Response.Output);
if (result != null) {
result.ViewEngine.ReleaseView(context, View);
}
}
ASP.NET MVC的视图引擎
从上一小节中,看到要想得到IView对象,必须先有ViewEngineResult对象,而ViewEngineResult对象是通过ViewResult类的FindView方法得到的:
protected override ViewEngineResult FindView(ControllerContext context) {
ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName);
if (result.View != null) {
return result;
}
// we need to generate an exception containing all the locations we searched
StringBuilder locationsText = new StringBuilder();
foreach (string location in result.SearchedLocations) {
locationsText.AppendLine();
locationsText.Append(location);
}
throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
MvcResources.Common_ViewNotFound, ViewName, locationsText));
}
从ViewResult类的FindView方法中,得知ViewEngineResult是通过ViewEngineCollection的FindView得到的,而ViewEngineCollection正是ViewEngines的静态属性Engines,Engines返回一个只有一个WebFormViewEngine类型实例的一个集合。所以,ViewEngineResult会是调用WebFormViewEngine类的FindView方法返回的结果。如果ViewEngins的静态属性Engines有多个ViewEngine提供,那么就依次遍历它们直到找到第一个不为空的ViewEngineResult为止。这样我们就可以在同一个MVC网站中使用多种视图引擎了。
在WebFormViewEngine的FindView方法返回之前,它会为ViewEngineResult注入一个IView类型的WebFormView实例,这样ViewEngineResult就作为一个中间人把IView类型给ViewResult了,然后ViewResult借助IView的力量,把数据输出给用户。
它们的关系是: