public
class MvcRouteHandler : IRouteHandler {
protected
virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
return
new MvcHandler(requestContext);
}
#region IRouteHandler Members
IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) {
return GetHttpHandler(requestContext);
}
#endregion
}
从源码里我们可以看出,MvcRouteHandler返回了MvcHandler实例并传递RequestContext参数, 然后转到MvcHandler的ProcessRequest(HttpContext httpContext)方法中, 并在这个方法里根据httpContext创建了HttpContextWrapper(继承于HttpContextBase)实例, 源码如下:
protected
internal
virtual
void ProcessRequest(HttpContextBase httpContext) {
AddVersionHeader(httpContext);
//
Get the controller type
string controllerName = RequestContext.RouteData.GetRequiredString(
"
controller
");
//
Instantiate the controller and call Execute
IControllerFactory factory = ControllerBuilder.GetControllerFactory();
IController controller = factory.CreateController(RequestContext, controllerName);
if (controller ==
null) {
throw
new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
factory.GetType(),
controllerName));
}
try {
controller.Execute(RequestContext);
}
finally {
factory.ReleaseController(controller);
}
}
Controller解析执行就是从这里开始的了,是ASP.NET MVC处理请求的关键部分, 我们现在逐条分析代码,根据执行顺序一步一步揭开它神秘的面纱, 首先看看ControllerBuilder类部分代码:
public
class ControllerBuilder {
private Func<IControllerFactory> _factoryThunk;
private
static ControllerBuilder _instance =
new ControllerBuilder();
private HashSet<
string> _namespaces =
new HashSet<
string>(StringComparer.OrdinalIgnoreCase);
public ControllerBuilder() {
SetControllerFactory(
new DefaultControllerFactory() {
ControllerBuilder =
this
});
}
public
static ControllerBuilder Current {
get {
return _instance;
}
}
[SuppressMessage(
"
Microsoft.Design
",
"
CA1024:UsePropertiesWhereAppropriate
",
Justification =
"
Calling method multiple times might return different objects.
")]
public IControllerFactory GetControllerFactory() {
IControllerFactory controllerFactoryInstance = _factoryThunk();
return controllerFactoryInstance;
}
public
void SetControllerFactory(IControllerFactory controllerFactory) {
if (controllerFactory ==
null) {
throw
new ArgumentNullException(
"
controllerFactory
");
}
_factoryThunk = () => controllerFactory;
}
}
默认情况下ControllerBuilder.GetControllerFactory()是返回的DefaultControllerFactory实例,接着再往下看:
IController controller = factory.CreateController(RequestContext, controllerName);
它是如何创建controller的呢? 看看的DefaultControllerFactory源码就知道了.
public
virtual IController CreateController(RequestContext requestContext,
string controllerName) {
if (requestContext ==
null) {
throw
new ArgumentNullException(
"
requestContext
");
}
if (String.IsNullOrEmpty(controllerName)) {
throw
new ArgumentException(MvcResources.Common_NullOrEmpty,
"
controllerName
");
}
RequestContext = requestContext;
Type controllerType = GetControllerType(controllerName);
IController controller = GetControllerInstance(controllerType);
return controller;
}
这里调用了GetControllerType()和GetControllerInstance()方法来创建controller,在GetControllerType方法中主要是一行代码:return GetControllerTypeWithinNamespaces(controllerName, null /* namespaces */);那我们也看看它做了些什么动作.
private Type GetControllerTypeWithinNamespaces(
string controllerName, HashSet<
string> namespaces) {
//
Once the master list of controllers has been created we can quickly index into it
ControllerTypeCache.EnsureInitialized(BuildManager);
IList<Type> matchingTypes = ControllerTypeCache.GetControllerTypes(controllerName, namespaces);
...
}
它主要是调用了ControllerTypeCache中的两个方法,在EnsureInitialized方法中调用了GetAllControllerTypes(BuildManager)方法从BuildManager中获取所有程序集中public, not abstract并且以"Controller"结尾的Type放入列表中进行缓存,ControllerTypeCache.GetControllerTypes(controllerName, namespaces)主要是从缓存的字典中读取对应的Controller.
接着在GetControllerInstance方法中调用Activator.CreateInstance静态方法创建Controller, 然后执行Controller的Execute方法,Execute方法是IController接口中定义的方法, ControllerBase类实现了此方法并提供了TempData和ViewData属性, Execute实现如下:
protected
virtual
void Execute(RequestContext requestContext) {
if (requestContext ==
null) {
throw
new ArgumentNullException(
"
requestContext
");
}
Initialize(requestContext);
ExecuteCore();
}
Initialize方法根据RequestContext创建了ControllerContext对象, ControllerContext有4个属性:
public virtual ControllerBase Controller; //初始化时传入
public virtual HttpContextBase HttpContext; //默认为RequestContext.HttpContext或EmptyHttpContext
public RequestContext RequestContext ; //初始化时传入
public virtual RouteData RouteData; //默认为RequestContext.RouteData
ExecuteCore()是ControllerBase的抽象方法,Controller类实现了此方法,实现如下:
protected
override
void ExecuteCore() {
TempData.Load(ControllerContext, TempDataProvider);
try {
string actionName = RouteData.GetRequiredString(
"
action
");
if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
HandleUnknownAction(actionName);
}
}
finally {
TempData.Save(ControllerContext, TempDataProvider);
}
}
在ExecuteCore()中实现了TempData的Load和Save, 所以TempData才可以在其他的View中有效,而ViewData只能在对应的View中有效. ActionInvoker是Controller中的属性, 其默认为ControllerActionInvoker实例, 我们接着再看看ActionInvoker.InvokeAction(ControllerContext, actionName)又是怎么找到Action的呢? 还是从源码入手:
public
virtual
bool InvokeAction(ControllerContext controllerContext,
string actionName) {
ControllerDescriptor controllerDescriptor = GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor = FindAction(controllerContext, controllerDescriptor, actionName);
if (actionDescriptor !=
null) {
FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
try {
AuthorizationContext authContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
if (authContext.Result !=
null) {
//
the auth filter signaled that we should let it short-circuit the request
InvokeActionResult(controllerContext, authContext.Result);
}
else {
if (controllerContext.Controller.ValidateRequest) {
ValidateRequest(controllerContext.HttpContext.Request);
}
IDictionary<
string,
object> parameters = GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);
InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, postActionContext.Result);
}
}
return
true;
}
//
notify controller that no method matched
return
false;
}
GetControllerDescriptor(controllerContext)方法调用DescriptorCache.GetDescriptor()并返回了ReflectedControllerDescriptor(继承于ControllerDescriptor)实例,并在其Cache属性中保存了ReflectedControllerDescriptor实例. ReflectedControllerDescriptor类中有一个ActionMethodSelector类型的私用变量_selector, 在ActionMethodSelector构造方法中调用ControllerType.GetMethods方法得到了Controller中的所有方法并过滤出Action方法存储到AliasedMethods和NonAliasedMethods属性中, 用于查询Action.而FindAction(controllerContext, controllerDescriptor, actionName)最终也是调用了ControllerDescriptor中的FindAction(),而这里的ControllerDescriptor始终是ReflectedControllerDescriptor, 所以我们找到ReflectedControllerDescriptor的FindAction方法:
public
override ActionDescriptor FindAction(ControllerContext controllerContext,
string actionName) {
if (controllerContext ==
null) {
throw
new ArgumentNullException(
"
controllerContext
");
}
if (String.IsNullOrEmpty(actionName)) {
throw
new ArgumentException(MvcResources.Common_NullOrEmpty,
"
actionName
");
}
MethodInfo matched = _selector.FindActionMethod(controllerContext, actionName);
if (matched ==
null) {
return
null;
}
return
new ReflectedActionDescriptor(matched, actionName,
this);
}
可以看出, 它是调用ActionMethodSelector的FindActionMethod然后构造新的ReflectActionDescriptor返回的,在ActionMethodSelector的FindActionMethod方法里就用到了刚才提到了AliasedMethods和NonAliasedMethods属性找出相匹配的方法, 再回到InvokeAction继续往下看执行的是GetFilters将controller添加到4个基本Filter列表中去:
protected
virtual FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
FilterInfo filters = actionDescriptor.GetFilters();
//
if the current controller implements one of the filter interfaces, it should be added to the list at position 0
ControllerBase controller = controllerContext.Controller;
AddControllerToFilterList(controller, filters.ActionFilters);
AddControllerToFilterList(controller, filters.ResultFilters);
AddControllerToFilterList(controller, filters.AuthorizationFilters);
AddControllerToFilterList(controller, filters.ExceptionFilters);
return filters;
}
FilterInfo类只有四个List属性, 分别是:
public IList<IActionFilter> ActionFilters;
public IList<IAuthorizationFilter> AuthorizationFilters;
public IList<IExceptionFilter> ExceptionFilters;
public IList<IResultFilter> ResultFilters;
再接着执行GetParameterValues(controllerContext, actionDescriptor), 在这个方法里获取Action参数并实现Model绑定,GetParameterValue代码如下:
protected
virtual
object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) {
//
collect all of the necessary binding properties
Type parameterType = parameterDescriptor.ParameterType;
IModelBinder binder = GetModelBinder(parameterDescriptor);
IDictionary<
string, ValueProviderResult> valueProvider = controllerContext.Controller.ValueProvider;
string parameterName = parameterDescriptor.BindingInfo.Prefix ?? parameterDescriptor.ParameterName;
Predicate<
string> propertyFilter = GetPropertyFilter(parameterDescriptor);
//
finally, call into the binder
ModelBindingContext bindingContext =
new ModelBindingContext() {
FallbackToEmptyPrefix = (parameterDescriptor.BindingInfo.Prefix ==
null),
//
only fall back if prefix not specified
ModelName = parameterName,
ModelState = controllerContext.Controller.ViewData.ModelState,
ModelType = parameterType,
PropertyFilter = propertyFilter,
ValueProvider = valueProvider
};
object result = binder.BindModel(controllerContext, bindingContext);
return result;
}
接着由InvokeActionMethodWithFilters转到InvokeActionMethodFilter执行filter.OnActionExecuting(即controller),然后从InvokeActionMethodf中执行ActionDescriptor的抽象方法Execute()并创建ActionResult返回.
在Execute方法中会创建ActionMethodDispatcher对象, 在ActionMethodDispatcher构造函数中传入Aciton方法, 再调用ActionMethodDispatcher的Execute进入具体的Action方法(即Controller的Action方法), 现由Controller的View方法创建ViewResult对象返回:
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
};
}
到此Action执行结束, 执OnActionExecuted()方法,再回到InvokeAction执行InvokeActionResultWithFilters, 这时OnResultExecuting()就开始运行了,OnResultExecuting执行完了后, 就执行ActionResult.ExecuteResult, 从上面代码可以知道View方法返回的是ViewResult,ExecuteResult是在ActionResult类中定义的抽象方法, ViewResultBase实现了此方法查找ViewEngine及对View调用Render.
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);
}
}
FindView是ViewResultBase中定义的抽象方法,在ViewResult中的实现如下:
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));
}
调用了ViewEngineCollection.FindView, ViewEngineCollection是ViewResultBase中的属性:
public ViewEngineCollection ViewEngineCollection {
get {
return _viewEngineCollection ?? ViewEngines.Engines;
}
set {
_viewEngineCollection = value;
}
}
默认情况下是ViewEngines的静态属性Engines, 所以在自定义视图引挚时, 我们一般都会在Globol.cs中的Application_Start()中将自己定义的视图引挚添加到ViewEngines.Engines中去, ASP.NET MVC默认情况下就有new WebFormViewEngine().
public
static
class ViewEngines {
private
readonly
static ViewEngineCollection _engines =
new ViewEngineCollection {
new WebFormViewEngine()
};
public
static ViewEngineCollection Engines {
get {
return _engines;
}
}
}
WebFromViewEngine继承于VirtualPathProviderViewEngine, 而VirtualPathProviderViewEngine继承了IViewEngine, 并实现了IViewEngine的FindView,FindPartialView及ReleaseView, 还提供了MasterLocaltionFormats,PartialViewLocationFormats和ViewLocationFormats属性, 通常我们自定义的视图引挚可以继承于VirtualPathProviderViewEngine, ViewEngineCollection.FindView遍历所有的ViewEngine, 并调用ViewEngine.FindView根据返回的字符串数组创建ViewEngineResult对象返回, 默认情况下ViewEngineCollection只有一个ViewEngine(WebFromViewEngine), 所以我们找到VirtualPathProviderViewEngine的FindView实现:
public
virtual ViewEngineResult FindView(ControllerContext controllerContext,
string viewName,
string masterName,
bool useCache) {
string[] viewLocationsSearched;
string[] masterLocationsSearched;
string controllerName = controllerContext.RouteData.GetRequiredString(
"
controller
");
string viewPath = GetPath(controllerContext, ViewLocationFormats,
"
ViewLocationFormats
", viewName, controllerName, _cacheKeyPrefix_View, useCache,
out viewLocationsSearched);
string masterPath = GetPath(controllerContext, MasterLocationFormats,
"
MasterLocationFormats
", masterName, controllerName, _cacheKeyPrefix_Master, useCache,
out masterLocationsSearched);
if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName))) {
return
new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
}
return
new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath),
this);
}
GetPath根据ViewLocationFormats数据顺序查找到第一个符合条件的就返回, CreateView是VirtualPathProviderViewEngine提供的抽象函数, 需要在自定义的ViewEngine中实现, WebFormViewEngine实现如下:
protected
override IView CreateView(ControllerContext controllerContext,
string viewPath,
string masterPath) {
return
new WebFormView(viewPath, masterPath);
}
ViewEngineResult类中只包含了三个属性:
public IEnumerable<string> SearchedLocations;
public IView View;
public IViewEngine ViewEngine;
FindView后返回到ExecuteResult方法中执行View.Render方法并传入了ViewContext(ControllerContext, View, ViewData, TempData),在WebFormView.Render中创建ViewPage对象并输出,关键代码如下:
public
virtual
void Render(ViewContext viewContext, TextWriter writer) {
object viewInstance = BuildManager.CreateInstanceFromVirtualPath(ViewPath,
typeof(
object));
ViewPage viewPage = viewInstance
as ViewPage;
if (viewPage !=
null) {
RenderViewPage(viewContext, viewPage);
return;
}
ViewUserControl viewUserControl = viewInstance
as ViewUserControl;
if (viewUserControl !=
null) {
RenderViewUserControl(viewContext, viewUserControl);
return;
}
throw
new InvalidOperationException(
String.Format(
CultureInfo.CurrentUICulture,
MvcResources.WebFormViewEngine_WrongViewBase,
ViewPath));
}
RenderViewPage(viewContext, viewPage)方法:
private
void RenderViewPage(ViewContext context, ViewPage page) {
if (!String.IsNullOrEmpty(MasterPath)) {
page.MasterLocation = MasterPath;
}
page.ViewData = context.ViewData;
page.RenderView(context);
}
代码page.ViewData = context.ViewData就将Controller的ViewData传递到ViewPage中了, 因此我们可以在aspx页面使用Controller中的ViewData,TempData属性实质返回的是ViewPage中的ViewContext.TempData. 在ViewPage.RenderView对HtmlHelper,AjaxHelper和UrlHelper进行初始化后,就调用ProcessRequest开始进行页面处理,如OnPreInit, OnPreRender事件等, 最后再执OnResultExecuted,整个ASP.NET MVC调用流程到此就结束了.