这次探险历程将从 MvcHandler 开始。
{
protected virtual void ProcessRequest(HttpContext httpContext)
{
HttpContextBase base2 = new HttpContextWrapper2(httpContext);
this.ProcessRequest(base2);
}
protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
IControllerFactory controllerFactory = this.ControllerBuilder.GetControllerFactory();
IController controller = controllerFactory.CreateController(this.RequestContext, requiredString);
if (controller == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,
MvcResources.ControllerBuilder_FactoryReturnedNull,
new object[] { controllerFactory.GetType(), requiredString }));
}
try
{
ControllerContext controllerContext = new ControllerContext(this.RequestContext, controller);
controller.Execute(controllerContext);
}
finally
{
controllerFactory.DisposeController(controller);
}
}
}
首 先从 RouteData 中提取 Controller 的名字(这个名字是我们在 Global.asax.cs RegisterRoutes 中注册 Route 时提供的),然后获取 ControllerFactory,只不过这里面专门提供了一个 ControllerBuilder。
{
get
{
if (this._controllerBuilder == null)
{
this._controllerBuilder = ControllerBuilder.Current;
}
return this._controllerBuilder;
}
set
{
this._controllerBuilder = value;
}
}
除非我们自定义 MvcHandler,否则就直接去看看这个 ControllerBuilder.Current 吧。
{
// Fields
private Func<IControllerFactory> _factoryThunk;
private static ControllerBuilder _instance = new ControllerBuilder();
// Methods
public ControllerBuilder()
{
this.SetControllerFactory(new DefaultControllerFactory());
}
public IControllerFactory GetControllerFactory()
{
return this._factoryThunk();
}
public void SetControllerFactory(Type controllerFactoryType)
{
// ….
this._factoryThunk = delegate
{
IControllerFactory factory;
try
{
factory = (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
}
catch (Exception exception)
{
// …
}
return factory;
};
}
public void SetControllerFactory(IControllerFactory controllerFactory)
{
// …
this._factoryThunk = () => controllerFactory;
}
// Properties
public static ControllerBuilder Current
{
get { return _instance; }
}
}
嗯,有点意思。剔除掉无关紧要的代码,这个 ControllerBuilder 告诉我们如下事实。
(1) 通常情况下,返回一个默认的 DefaultControllerFactory 实例。
(2) 我们可以在 Application_Start 中通过 ControllerBuilder.Current.SetControllerFactory 方法来注册一个我们自定义的工厂。
(3) 核心代码: factory = (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
好 了,回到前面的流程。MvcHandler.ProcessRequest 是通过 DefaultControllerFactory.CreateController(RequestContext, requiredString) 来返回 IController 实例。那么我们就看看这个 DefaultControllerFactory.CreateController 又有什么玄机。
{
protected internal virtual IController CreateController(RequestContext requestContext, string controllerName)
{
//…
this.RequestContext = requestContext;
Type controllerType = this.GetControllerType(controllerName);
return this.GetControllerInstance(controllerType);
}
protected internal virtual Type GetControllerType(string controllerName)
{
Type type2;
// …
if (!this.ControllerTypeCache.Initialized)
{
// … 自己打开 Reflector 看吧 …
}
if (!this.ControllerTypeCache.TryGetControllerType(controllerName, out type2))
{
return null;
}
// …
return type2;
}
protected internal virtual IController GetControllerInstance(Type controllerType)
{
IController controller;
//…
try
{
controller = Activator.CreateInstance(controllerType) as IController;
}
catch (Exception exception)
{
// …
}
return controller;
}
}
这 个实在没啥好说的,通过反射来创建 Controller 实例。唯一有点看头的就是 GetControllerType 里面做了些缓存处理,以此来避免频繁使用反射造成的性能问题。回到 MvcHandler.ProcessRequest(),在得到控制器实例后,MvcHandler 开始了调用 Controller.Execute() 来进一步触发后续操作,同时对其上下文进一步封装,除了前面创建的 RequestContext,还加上了当前这个 Controller 对象的引用。
{
protected internal virtual void Execute(ControllerContext controllerContext)
{
//…
string requiredString = this.RouteData.GetRequiredString("action");
if (!this.InvokeAction(requiredString))
{
this.HandleUnknownAction(requiredString);
}
}
}
获取 Action 的名字,然后开始执行 InvokeAction。
{
return this.InvokeAction(actionName, new RouteValueDictionary());
}
protected internal virtual bool InvokeAction(string actionName, RouteValueDictionary values)
{
// …
MemberInfo[] infoArray = base.GetType().GetMember(actionName, MemberTypes.Method, …);
MethodInfo methodInfo = null;
foreach (MemberInfo info2 in infoArray)
{
MethodInfo info3 = (MethodInfo)info2;
if ((!info3.IsDefined(typeof(NonActionAttribute), true) && !info3.IsSpecialName) &&
info3.DeclaringType.IsSubclassOf(typeof(Controller)))
{
if (methodInfo != null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture,
MvcResources.Controller_MoreThanOneAction,
new object[] { actionName, base.GetType() }));
}
methodInfo = info3;
}
}
if (methodInfo != null)
{
this.InvokeActionMethod(methodInfo, values);
return true;
}
return false;
}
这 段代码还是很有趣的。首先,它通过反射获取所有同名 Action 方法信息;其次,它过滤掉所有有 NonActionAttribute 和 IsSpecialName 标记的方法;第三,当同名有效 Action 被重载时它会抛出异常 —— 提示 "Controller_MoreThanOneAction"。
也就是说下面的写法是可以的。
{
public void About()
{
About(123);
}
[NonAction]
public void About(int x)
{
Response.Write("x…");
}
}
可一旦去掉那个 "[NonAction]",你将看到如下的异常信息。
继续 InvokeActionMethod,这个方法看上去很复杂,其实最核心的代码就最后一行,前面都是相关参数的分解。
{
// …
this.InvokeActionMethodFilters(methodInfo, delegate
{
methodInfo.Invoke(this, parameterValues);
});
}
这行代码将 Action 的调用作为一个委托,连同反射信息传递给 InvokeActionMethodFilters。
{
List<ActionFilterAttribute> filters = new List<ActionFilterAttribute>
{
new ControllerActionFilter(this)
};
Stack<MemberInfo> memberChain = new Stack<MemberInfo>();
for (Type type = base.GetType(); type != null; type = type.BaseType)
{
memberChain.Push(type);
}
List<ActionFilterAttribute> collection = SortActionFilters(memberChain);
filters.AddRange(collection);
List<ActionFilterAttribute> list3 = PrepareMethodActionFilters(methodInfo);
filters.AddRange(list3);
FilterContext context = new FilterContext(this.ControllerContext, methodInfo);
new ActionFilterExecutor(filters, context, continuation).Execute();
}
这 个方法首先将默认的过滤器 ControllerActionFilter 加到列表,然后提取所有继承层次上基类的过滤器特性。最后将这些过滤器集合、过滤上下文,连同前一个方法传递进来的 Action 执行委托(continuation) 再次转交给了一个 ActionFilterExecutor 对象实例,并调用其 Execute 方法。
{
// Fields
private FilterContext _context;
private Action _continuation;
private List<ActionFilterAttribute> _filters;
// Methods
public ActionFilterExecutor(List<ActionFilterAttribute> filters, FilterContext context, Action continuation)
{
this._filters = filters;
this._context = context;
this._continuation = continuation;
}
public void Execute()
{
IEnumerator<ActionFilterAttribute> enumerator = this._filters.GetEnumerator();
this.ExecuteRecursive(enumerator);
}
private FilterExecutedContext ExecuteRecursive(IEnumerator<ActionFilterAttribute> enumerator)
{
01: if (enumerator.MoveNext())
02: {
03: ActionFilterAttribute current = enumerator.Current;
04: FilterExecutingContext filterContext = new FilterExecutingContext(this._context);
05: current.OnActionExecuting(filterContext);
06:
07: if (filterContext.Cancel)
08: {
09: return new FilterExecutedContext(this._context, null);
10: }
11:
12: bool flag = false;
13: FilterExecutedContext context2 = null;
14: try
15: {
16: context2 = this.ExecuteRecursive(enumerator);
17: }
18: catch (Exception exception)
19: {
20: flag = true;
21: context2 = new FilterExecutedContext(this._context, exception);
22: current.OnActionExecuted(context2);
23: if (!context2.ExceptionHandled)
24: {
25: throw;
26: }
27: }
28:
29: if (!flag)
30: {
31: current.OnActionExecuted(context2);
32: }
33: return context2;
34: }
35:
36: this._continuation();
37: return new FilterExecutedContext(this._context, null);
}
}
ExecuteRecursive 看上去不大容易理解。不过对于习惯使用递归的人来说,也不是什么难事。
(1) 通过迭代器 MoveNext() 方法提取一个过滤器对象,执行其 OnActionExecuting 方法。
(2) 如果该方法设置了 filterContext.Cancel = true,则放弃后续执行代码。这种机制为我们提供了更好的控制(Preview 1 通过 Context.OnPreAction 的返回值来做同样的控制,现已废弃),比如写一个 CacheFilterAttribute,在缓存未过期时直接输出静态内容,并终止后续执行。(我会在后面章节,提供一个可用的缓存过滤器代码)
(3) 进入第 16 行递归调用,这样一来,就可以一层一层调用所有的 ActionFilterAttribute.OnActionExecuting 方法,直到 MoveNext() == false。
(4) 在最后一次递归调用时,由于 enumerator.MoveNext() == false,故 36 行的 _continuation() 方法得以被执行。还记得这个方法吗?就是前面给传递过来的 Action 方法委托,这意味着我们写的 Action 方法总算是执行了。这个方法是我们这一章流程分析的终点。
(5) 在 Action 委托执行完成后,递归调用自 29 行恢复,逐级往上回溯,直到最初那个方法堆栈。这样所有 ActionFilterAttribute.OnActionExecuted 也被执行完成。
好了,到此为止,我们基本完成了 "核心" 部分的流程分析过程。虽然简单了些,但对于我们理解 ASP.NET MVC 执行机制和原理还是很有必要的。下一章的分析,就得从那个 Action Delegate 开始了。
—————–
附: 流程分析图