ASP.NET MVC Preview 2 - 流程分析 (2)
2008-04-30 13:17 Jacky_Xu 阅读(717) 评论(0) 编辑 收藏 举报
这次探险历程将从 MvcHandler 开始。
首先从 RouteData 中提取 Controller 的名字(这个名字是我们在 Global.asax.cs RegisterRoutes 中注册 Route 时提供的),然后获取 ControllerFactory,只不过这里面专门提供了一个 ControllerBuilder。
除非我们自定义 MvcHandler,否则就直接去看看这个 ControllerBuilder.Current 吧。
嗯,有点意思。剔除掉无关紧要的代码,这个 ControllerBuilder 告诉我们如下事实。
(1) 通常情况下,返回一个默认的 DefaultControllerFactory 实例。
(2) 我们可以在 Application_Start 中通过 ControllerBuilder.Current.SetControllerFactory 方法来注册一个我们自定义的工厂。
(3) 核心代码: factory = (IControllerFactory)Activator.CreateInstance(controllerFactoryType);
好了,回到前面的流程。MvcHandler.ProcessRequest 是通过 DefaultControllerFactory.CreateController(RequestContext, requiredString) 来返回 IController 实例。那么我们就看看这个 DefaultControllerFactory.CreateController 又有什么玄机。
这个实在没啥好说的,通过反射来创建 Controller 实例。唯一有点看头的就是 GetControllerType 里面做了些缓存处理,以此来避免频繁使用反射造成的性能问题。回到 MvcHandler.ProcessRequest(),在得到控制器实例后,MvcHandler 开始了调用 Controller.Execute() 来进一步触发后续操作,同时对其上下文进一步封装,除了前面创建的 RequestContext,还加上了当前这个 Controller 对象的引用。
获取 Action 的名字,然后开始执行 InvokeAction。
这段代码还是很有趣的。首先,它通过反射获取所有同名 Action 方法信息;其次,它过滤掉所有有 NonActionAttribute 和 IsSpecialName 标记的方法;第三,当同名有效 Action 被重载时它会抛出异常 —— 提示 "Controller_MoreThanOneAction"。
也就是说下面的写法是可以的。
可一旦去掉那个 "[NonAction]",你将看到如下的异常信息。
继续 InvokeActionMethod,这个方法看上去很复杂,其实最核心的代码就最后一行,前面都是相关参数的分解。
这行代码将 Action 的调用作为一个委托,连同反射信息传递给 InvokeActionMethodFilters。
这个方法首先将默认的过滤器 ControllerActionFilter 加到列表,然后提取所有继承层次上基类的过滤器特性。最后将这些过滤器集合、过滤上下文,连同前一个方法传递进来的 Action 执行委托(continuation) 再次转交给了一个 ActionFilterExecutor 对象实例,并调用其 Execute 方法。
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 开始了。
-----------------
附: 流程分析图
查看大图
public class MvcHandler : IHttpHandler, IRequiresSessionState
{
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);
}
}
}
{
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。
internal ControllerBuilder ControllerBuilder
{
get
{
if (this._controllerBuilder == null)
{
this._controllerBuilder = ControllerBuilder.Current;
}
return this._controllerBuilder;
}
set
{
this._controllerBuilder = value;
}
}
{
get
{
if (this._controllerBuilder == null)
{
this._controllerBuilder = ControllerBuilder.Current;
}
return this._controllerBuilder;
}
set
{
this._controllerBuilder = value;
}
}
除非我们自定义 MvcHandler,否则就直接去看看这个 ControllerBuilder.Current 吧。
public class ControllerBuilder
{
// 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; }
}
}
{
// 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 又有什么玄机。
public class DefaultControllerFactory : IControllerFactory
{
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;
}
}
{
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 对象的引用。
public class Controller : IController
{
protected internal virtual void Execute(ControllerContext controllerContext)
{
//...
string requiredString = this.RouteData.GetRequiredString("action");
if (!this.InvokeAction(requiredString))
{
this.HandleUnknownAction(requiredString);
}
}
}
{
protected internal virtual void Execute(ControllerContext controllerContext)
{
//...
string requiredString = this.RouteData.GetRequiredString("action");
if (!this.InvokeAction(requiredString))
{
this.HandleUnknownAction(requiredString);
}
}
}
获取 Action 的名字,然后开始执行 InvokeAction。
protected internal bool InvokeAction(string actionName)
{
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;
}
{
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 class HomeController : Controller
{
public void About()
{
About(123);
}
[NonAction]
public void About(int x)
{
Response.Write("x...");
}
}
{
public void About()
{
About(123);
}
[NonAction]
public void About(int x)
{
Response.Write("x...");
}
}
可一旦去掉那个 "[NonAction]",你将看到如下的异常信息。
More than one action named 'About' was found on controller 'Rainsoft.Web.Controllers.HomeController'.
继续 InvokeActionMethod,这个方法看上去很复杂,其实最核心的代码就最后一行,前面都是相关参数的分解。
protected internal virtual void InvokeActionMethod(MethodInfo methodInfo, RouteValueDictionary values)
{
// ...
this.InvokeActionMethodFilters(methodInfo, delegate
{
methodInfo.Invoke(this, parameterValues);
});
}
{
// ...
this.InvokeActionMethodFilters(methodInfo, delegate
{
methodInfo.Invoke(this, parameterValues);
});
}
这行代码将 Action 的调用作为一个委托,连同反射信息传递给 InvokeActionMethodFilters。
private void InvokeActionMethodFilters(MethodInfo methodInfo, Action continuation)
{
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();
}
{
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 方法。
internal sealed class ActionFilterExecutor
{
// 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);
}
}
{
// 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 开始了。
-----------------
附: 流程分析图
查看大图