了解.net MVC的实现原理Controller/Action

通过Reflector反编译,我们对IIS分发请求至w3wp.exe进程之后交由HttpRuntime处理过程的分析了解HttpApplication,HttpModule,HttpHandler,HttpContext的生成机制。那我们继续来了解.net MVC 路由的如何实现URL跳转到指定的Controller/Action过程。

  • UrlRoutingModule
  • MvcRoutingHandler
  • MvcHandler
  • Controller

一、UrlRoutingModule

当所有HttpModule被HttpApplication首次加载后,每个HttpModule会在自己的Init方法中注册HttpApplication事件实现对HttpRequest请求的拦截。当然UrlRoutingModule也不例外。我们反编译一下UrlRoutingModule源码 

View Code
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
public class UrlRoutingModule : IHttpModule
{
// Fields
private static readonly object _requestDataKey = new object();
private RouteCollection _routeCollection;

// Methods
protected virtual void Dispose()
{
}

protected virtual void Init(HttpApplication application)
{
application.PostResolveRequestCache
+= new EventHandler(this.OnApplicationPostResolveRequestCache);
application.PostMapRequestHandler
+= new EventHandler(this.OnApplicationPostMapRequestHandler);
}

private void OnApplicationPostMapRequestHandler(object sender, EventArgs e)
{
HttpContextBase context
= new HttpContextWrapper(((HttpApplication) sender).Context);
this.PostMapRequestHandler(context);
}

private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
HttpContextBase context
= new HttpContextWrapper(((HttpApplication) sender).Context);
this.PostResolveRequestCache(context);
}

public virtual void PostMapRequestHandler(HttpContextBase context)
{
RequestData data
= (RequestData) context.Items[_requestDataKey];
if (data != null)
{
context.RewritePath(data.OriginalPath);
context.Handler
= data.HttpHandler;
}
}

public virtual void PostResolveRequestCache(HttpContextBase context)
{
RouteData routeData
= this.RouteCollection.GetRouteData(context);
if (routeData != null)
{
IRouteHandler routeHandler
= routeData.RouteHandler;
if (routeHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoRouteHandler, new object[0]));
}
if (!(routeHandler is StopRoutingHandler))
{
RequestContext requestContext
= new RequestContext(context, routeData);
IHttpHandler httpHandler
= routeHandler.GetHttpHandler(requestContext);
if (httpHandler == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, RoutingResources.UrlRoutingModule_NoHttpHandler, new object[] { routeHandler.GetType() }));
}
RequestData data2
= new RequestData();
data2.OriginalPath
= context.Request.Path;
data2.HttpHandler
= httpHandler;
context.Items[_requestDataKey]
= data2;
context.RewritePath(
"~/UrlRouting.axd");
}
}
}

void IHttpModule.Dispose()
{
this.Dispose();
}

void IHttpModule.Init(HttpApplication application)
{
this.Init(application);
}

// Properties
public RouteCollection RouteCollection
{
get
{
if (this._routeCollection == null)
{
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
{
this._routeCollection = value;
}
}

// Nested Types
private class RequestData
{
// Fields
[CompilerGenerated]
private IHttpHandler <HttpHandler>k__BackingField;
[CompilerGenerated]
private string <OriginalPath>k__BackingField;

// Properties
public IHttpHandler HttpHandler
{
[CompilerGenerated]
get
{
return this.<HttpHandler>k__BackingField;
}
[CompilerGenerated]
set
{
this.<HttpHandler>k__BackingField = value;
}
}

public string OriginalPath
{
[CompilerGenerated]
get
{
return this.<OriginalPath>k__BackingField;
}
[CompilerGenerated]
set
{
this.<OriginalPath>k__BackingField = value;
}
}
}
}

可以看到UrlRoutingModule订阅的两个 HttpApplication 事件。其中PostResolveRequestCache 要比 PostMapRequestHandler 先执行,先看PostResolveRequestCache 事件,他首先从首先从 RouteCollection 中获取一个 RouteData 对象。而RouteCollection是通过路由表创建的

// Properties
public RouteCollection RouteCollection
{
get
{
if (this._routeCollection == null)
{
this._routeCollection = RouteTable.Routes;
}
return this._routeCollection;
}
set
{
this._routeCollection = value;
}
}

我们在Global.asax.cs注册路由的时候(即HttpApplication),就已经往RouteTable.Routes添加了新的路由信息了,因此HttpModule可以从自己的RouteCollection查找到对应请求的路由。RouteTable只有一个静态集合属性RouteCollection。

View Code
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute(
"{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

}

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);

}
}

UrlRoutingModule 在 PostResolveRequestCache方法读取  RouteData routeData = this.RouteCollection.GetRouteData(context);

RouteData是包含了我们注册的每个Route的信息。在global中注册路由的时候,MapRote是RouteCollection扩展方法,默认使用了MvcRouteHandler。

public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
Route route2
= new Route(url, new MvcRouteHandler());
route2.Defaults
= new RouteValueDictionary(defaults);
route2.Constraints
= new RouteValueDictionary(constraints);
route2.DataTokens
= new RouteValueDictionary();
Route item
= route2;
if ((namespaces != null) && (namespaces.Length > 0))
{
item.DataTokens[
"Namespaces"] = namespaces;
}
routes.Add(name, item);
return item;
}

二、MvcRoutingHandler 

RouteData结构除了包含的Route信息还有默认的IRouteHandler即MvcRouteHandler。

在PostResolveRequestCache根据上下文比对查找到路由表中对应的RouteData后,并通过routeHandler.GetHttpHandler(requestContext)获得MvcHandler的实例。

View Code
public class MvcRouteHandler : IRouteHandler
{
// Methods
protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return new MvcHandler(requestContext);
}

IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
{
return this.GetHttpHandler(requestContext);
}
}

三、 MvcHandler

       从上面的过程可以看到UrlRouteModule每次拦截HttpApplication管线请求,先从RouteCollection找到与HttpContext请求对应的RouteData(包含MvcRouteHandler),并将HttpContextBase与RouteData封装为RequestContext,通过构造注入MvcHandler之中。MvcRouteHandler其实只起了一个过渡的作用,真正的工作是HttpApplication管线主导,在UrlRouteModule与MvcHandler之间进行的。

 UrlRouteModule在 PostResolveRequestCache方法中通过MvcRouteModule获取到MvcHandler的实例后,

RequestData data2 = new RequestData();
data2.OriginalPath
= context.Request.Path;
data2.HttpHandler
= httpHandler;
context.Items[_requestDataKey]
= data2;
context.RewritePath(
"~/UrlRouting.axd");

MvcHandler开始接管默认的WebForm的HttpHandler,注入到RequestData中并装入context.Items传递到管线中。而这个context对象之前也一并封装为RequestContext注入到了MvcHandler中,因此我们在MvcHandler后续过程中也可以取到上下文(Page或Controller等)。这个RequestData是UrlRouteModule的内部私有类,所以重载的时候没法实现它,如果想重写UrlRouteModule就要自己实现这个类了。

      至此,了解从UrlRouteModule到MvcRouteHandler再到MvcHandler的创建过程,但是最重要的问题MvcHandler是如何工作的?UrlRouteModule在拦截了HttpApplication的管线请求后,根据路由表找到了对由的RouteData(路由信息与MvcHandler),替换掉始终贯穿整个过程HttpContext中处理请求的HttpHandler,即MvcHandler。这些工作完成后,HttpApplication管线要继续处理Step事件,最终调用了MvcHandler 的ProcessRequest或BeginProcessRequest方法,从而进入到Controller的过程中。

      MvcHandler的触发过程:->HttpRuntime获取到HttpApplication->加载HttpModule,生成StepManager管线并加载MvcHandler->HttpRuntime调用HttpApplication.BeginProcessRequest->HttpApplication.StepManager.ResumeSteps

->执行StepManager中的HttpApplication.StepManager._execSteps[i].Execute ->MvcHandlers.ProcessRequest或BeginProcessRequest

下面是MvcHandler的反编译源码,可以看到除了要继承IHttpHandler,还继承了IRequireSeesionState 。自定义的HttpHandler想处理Session的话必须继承IRequireSeesionState。

View Code
public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState
{
// Fields
private ControllerBuilder _controllerBuilder;
private static readonly object _processRequestTag = new object();
[CompilerGenerated]
private static bool <DisableMvcResponseHeader>k__BackingField;
[CompilerGenerated]
private RequestContext <RequestContext>k__BackingField;
internal static readonly string MvcVersion = GetMvcVersionString();
public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version";

// Methods
public MvcHandler(RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
this.RequestContext = requestContext;
}

protected internal virtual void AddVersionHeader(HttpContextBase httpContext)
{
if (!DisableMvcResponseHeader)
{
httpContext.Response.AppendHeader(MvcVersionHeaderName, MvcVersion);
}
}

protected virtual IAsyncResult BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, object state)
{
HttpContextBase base2
= new HttpContextWrapper(httpContext);
return this.BeginProcessRequest(base2, callback, state);
}

protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state)
{
BeginInvokeDelegate delegate4
= null;
EndInvokeDelegate delegate5
= null;
Action action2
= null;
IController controller;
IControllerFactory factory;
this.ProcessRequestInit(httpContext, out controller, out factory);
IAsyncController asyncController
= controller as IAsyncController;
if (asyncController != null)
{
if (delegate4 == null)
{
delegate4
= delegate (AsyncCallback asyncCallback, object asyncState) {
IAsyncResult result;
try
{
result
= asyncController.BeginExecute(this.RequestContext, asyncCallback, asyncState);
}
catch
{
factory.ReleaseController(asyncController);
throw;
}
return result;
};
}
BeginInvokeDelegate beginDelegate
= delegate4;
if (delegate5 == null)
{
delegate5
= delegate (IAsyncResult asyncResult) {
try
{
asyncController.EndExecute(asyncResult);
}
finally
{
factory.ReleaseController(asyncController);
}
};
}
EndInvokeDelegate endDelegate
= delegate5;
SynchronizationContext synchronizationContext
= SynchronizationContextUtil.GetSynchronizationContext();
return AsyncResultWrapper.Begin(AsyncUtil.WrapCallbackForSynchronizedExecution(callback, synchronizationContext), state, beginDelegate, endDelegate, _processRequestTag);
}
if (action2 == null)
{
action2
= delegate {
try
{
controller.Execute(
this.RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
};
}
Action action
= action2;
return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
}

protected internal virtual void EndProcessRequest(IAsyncResult asyncResult)
{
AsyncResultWrapper.End(asyncResult, _processRequestTag);
}

private static string GetMvcVersionString()
{
return new AssemblyName(typeof(MvcHandler).Assembly.FullName).Version.ToString(2);
}

protected virtual void ProcessRequest(HttpContext httpContext)
{
HttpContextBase base2
= new HttpContextWrapper(httpContext);
this.ProcessRequest(base2);
}

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
this.ProcessRequestInit(httpContext, out controller, out factory);
try
{
controller.Execute(
this.RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
}

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
this.AddVersionHeader(httpContext);
this.RemoveOptionalRoutingParameters();
string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
factory
= this.ControllerBuilder.GetControllerFactory();
controller
= factory.CreateController(this.RequestContext, requiredString);
if (controller == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[] { factory.GetType(), requiredString }));
}
}

private void RemoveOptionalRoutingParameters()
{
RouteValueDictionary values
= this.RequestContext.RouteData.Values;
foreach (string str in values.Where<KeyValuePair<string, object>>(delegate (KeyValuePair<string, object> entry) {
return (entry.Value == UrlParameter.Optional);
}).Select
<KeyValuePair<string, object>, string>(delegate (KeyValuePair<string, object> entry) {
return entry.Key;
}).ToArray
<string>())
{
values.Remove(str);
}
}

IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb,
object extraData)
{
return this.BeginProcessRequest(context, cb, extraData);
}

void IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
{
this.EndProcessRequest(result);
}

void IHttpHandler.ProcessRequest(HttpContext httpContext)
{
this.ProcessRequest(httpContext);
}

// Properties
internal ControllerBuilder ControllerBuilder
{
get
{
if (this._controllerBuilder == null)
{
this._controllerBuilder = ControllerBuilder.Current;
}
return this._controllerBuilder;
}
set
{
this._controllerBuilder = value;
}
}

public static bool DisableMvcResponseHeader
{
[CompilerGenerated]
get
{
return <DisableMvcResponseHeader>k__BackingField;
}
[CompilerGenerated]
set
{
<DisableMvcResponseHeader>k__BackingField = value;
}
}

protected virtual bool IsReusable
{
get
{
return false;
}
}

public RequestContext RequestContext
{
[CompilerGenerated]
get
{
return this.<RequestContext>k__BackingField;
}
[CompilerGenerated]
private set
{
this.<RequestContext>k__BackingField = value;
}
}

bool IHttpHandler.IsReusable
{
get
{
return this.IsReusable;
}
}
}


四、Controller登场

看下MvcHandler的ProcessRequest或BeginProcessRequest, 我们看一下ProcessRequest方法的细节

protected internal virtual void ProcessRequest(HttpContextBase httpContext)
{
IController controller;
IControllerFactory factory;
this.ProcessRequestInit(httpContext, out controller, out factory);
try
{
controller.Execute(
this.RequestContext);
}
finally
{
factory.ReleaseController(controller);
}
}

private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory)
{
this.AddVersionHeader(httpContext);
this.RemoveOptionalRoutingParameters();
string requiredString = this.RequestContext.RouteData.GetRequiredString("controller");
factory
= this.ControllerBuilder.GetControllerFactory();
controller
= factory.CreateController(this.RequestContext, requiredString);
if (controller == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, MvcResources.ControllerBuilder_FactoryReturnedNull, new object[] { factory.GetType(), requiredString }));
}
}

主要是通过ProcessRequestInit 获取IControllerFactory 工厂,工厂再通过上下文中的地址反射Controller实例。那这个工厂哪里来的呢?

factory = this.ControllerBuilder.GetControllerFactory(); 看一下这个ControllerBuilder 是不是很熟悉? 看看Global.asax.cs的代码

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Threading;

namespace MvcApplication
{
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication
{
#region
public static void RegisterRoutes(RouteCollection routes)
{
//routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
#endregion

protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
//DefaultControllerFactory 每次都是根据上下文中的Action字符串反射Controller实例
//可以重写DefaultControllerFactory 利用IOC容器实现Controller实例化工作(提高效率)
ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory()); //Controller的反射工厂

}
}
}

一般大家会在这个时候把ControllerFactory注入,即使用默认的DefaultControllerFactory或自己利用IOC容器实现新的ControllerFactory工厂。
在ControllerFactory获取Controller并执行了 controller.Execute(this.RequestContext),就进入了Controller的具体业务了。

IController接口只有一个方法,ControllerBase继承IController,Controller又继承实现ControllerBase,而我们的具体业务的Controller名都是以文件夹名+Controller,并且继承了Controller。

public class AccountController : Controller
public class HomeController : Controller

如果想实现一现共用的业务比如:验证用户,验证权限等。我们可以再实现一个MyController继承基类Controller,然后其它的XXXController都继承这个MyController。当然也可以利用MVC提供的Filter机制(类似AOP拦截)来实现这些基本的业务验证,是不是比WebForm方便多了?

Execute方法只在ControllerBase中实现了,而Controller是直接继承的,我们的Controller也是直接继承的Controller。

View Code
protected virtual void Execute(RequestContext requestContext)
{
if (requestContext == null)
{
throw new ArgumentNullException("requestContext");
}
this.VerifyExecuteCalledOnce();
this.Initialize(requestContext);
this.ExecuteCore();
}

protected virtual void Initialize(RequestContext requestContext)
{
this.ControllerContext = new ControllerContext(requestContext, this);
}

protected abstract void ExecuteCore();

Execute主要的业务在放在了ExecuteCore中了,而这个ExecuteCore没有任何代码,只是在Controller中又被重载了业务。(看来ExecuteCore的业务还是被下放到了Controller中了,而Initalize只是RequestContext封装成ControllerContext,微软很有意思每一个环节都重新封装个上下文)。

在看Controller的ExecuteCore的业务

protected override void ExecuteCore()
{
this.PossiblyLoadTempData();
try
{
string requiredString = this.RouteData.GetRequiredString("action");
if (!this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString))
{
this.HandleUnknownAction(requiredString);
}
}
finally
{
this.PossiblySaveTempData();
}
}

public IActionInvoker ActionInvoker
{
get
{
if (this._actionInvoker == null)
{
this._actionInvoker = this.CreateActionInvoker();
}
return this._actionInvoker;
}
set
{
this._actionInvoker = value;
}
}

protected virtual IActionInvoker CreateActionInvoker()
{
return new ControllerActionInvoker();
}

ExectueCore调用this.ActionInvoker.InvokeAction(base.ControllerContext, requiredString)) 反射执行的ActionrequiredString参数为Action的名字

那这个Action被反射执行前后还有其它的业务吗? 记得我们在.net mvc中看到每个Action方法或者Controller基类被贴了一些属性标签,Action执行前后又触发了哪些方面呢?

·     Action执行前 ControllerOnActionExecuting先触发

·     Action执行后 ControllerOnActionExecuted被触发

·     Action执行前后 贴有继承ActionFilterAttribute属性标签中的OnActionExecutingOnActionExecuted被执行(还有其的Attribute如权限)

也就说ControllerActionInvoker InvokeAction方法在执行前还对ActionController进行了属性和Filter继承的扫描,来看InvokeAction的具体内容


View Code
public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(actionName))
{
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor
= this.GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor
= this.FindAction(controllerContext, controllerDescriptor, actionName);
if (actionDescriptor == null)
{
return false;
}
FilterInfo filters
= this.GetFilters(controllerContext, actionDescriptor);
try
{
AuthorizationContext context
= this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
if (context.Result != null)
{
this.InvokeActionResult(controllerContext, context.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
{
ValidateRequest(controllerContext);
}
IDictionary
<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
ActionExecutedContext context2
= this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, context2.Result);
}
}
catch (ThreadAbortException)
{
throw;
}
catch (Exception exception)
{
ExceptionContext context3
= this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);
if (!context3.ExceptionHandled)
{
throw;
}
this.InvokeActionResult(controllerContext, context3.Result);
}
return true;
}

ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor =
this.FindAction(controllerContext, controllerDescriptor, actionName);
上面两段代码是读取ControllerAction的所有描述信息包括标签属性

FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor); 这段代码是反射前面读到的所有具体的属性

ActionExecutedContext context2 = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);

通过InvokeActionMethodWithFilters 先执行Action前置拦截的方法,然后Action,接着后置拦截的方法。 是不是实现了AOP的部分功能了?当然它没做到AOP的环绕拦截功能,但相比WebForm却是进步了很多。

其实上面的InvokeAction具体怎么实现前后拦截我也没看出来,我是通过实现了两个类的重写跟进断点查看的。

五、重写ControllerControllerActionInvoker

下面是重写的代码 

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;

namespace MvcApplication.Module
{
public class MyController:Controller
{
public MyController()
{
//this.ActionInvoker = new MyControllerActionInvoker();
}

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
}

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}

/// <summary>
/// 具本的Action及前后拦截方法的调用者
/// </summary>
/// <returns></returns>
protected override IActionInvoker CreateActionInvoker()
{
return new MyControllerActionInvoker();
}
}

public class MyControllerActionInvoker : ControllerActionInvoker
{
public override bool InvokeAction(System.Web.Mvc.ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (string.IsNullOrEmpty(actionName))
{
//throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
}
ControllerDescriptor controllerDescriptor
= this.GetControllerDescriptor(controllerContext);
ActionDescriptor actionDescriptor
= this.FindAction(controllerContext, controllerDescriptor, actionName);
if (actionDescriptor == null)
{
return false;
}
//注意这里
FilterInfo filters = this.GetFilters(controllerContext, actionDescriptor);
try
{
AuthorizationContext context
= this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);
if (context.Result != null)
{
this.InvokeActionResult(controllerContext, context.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
{
//ValidateRequest(controllerContext);
}
IDictionary
<string, object> parameterValues = this.GetParameterValues(controllerContext, actionDescriptor);
//这里方法执行后,OnActionExecuting,OnActionExecuted,Action分别相应被触发
ActionExecutedContext context2 = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor, parameterValues);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, context2.Result);
}
}
catch (IOException ex)
{
throw;
}
catch (Exception exception)
{
ExceptionContext context3
= this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);
if (!context3.ExceptionHandled)
{
throw;
}
this.InvokeActionResult(controllerContext, context3.Result);
}
return true;

}
}

/// <summary>
/// 自定义拦截标签属性用于测试
/// </summary>
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
}
}
}

调试后进到MyControllerActionInvoker.InvokeAction 观察filters结构

 

当断点走到这个位置时

MyControllerFilterAttribute属性的OnActionExecuting先被执行,接着Action被执行,然后MyControllerFilterAttributeOnActionExecuted也被执行了。

从客户端请求到Controller的具体Action执行的流程基本上走了一遍,对.net mvc机制的也有了一定的了解,相信对.net mvc开发有很大帮助,至少在理解的基础上才能充分发挥他的优点及特性。下一节我们继续通过Refletor去了解Action的返回结果ActionResult是如何返回绑定值到视图以及视图引擎的机制。

.net MVC3 加入了很多新特性,例如客户端远程验证RemoteAttribute,新的视图引擎Razor等。

补充:Filter被读取后,要按照一定的顺序来执行。我们看一下ControllerActionInvoker的InvokeAction读取所有标签属性的方法

View Code
protected virtual FilterInfo GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
FilterInfo filters
= actionDescriptor.GetFilters();
ControllerBase controller
= controllerContext.Controller;
AddControllerToFilterList
<IActionFilter>(controller, filters.ActionFilters);
AddControllerToFilterList
<IResultFilter>(controller, filters.ResultFilters);
AddControllerToFilterList
<IAuthorizationFilter>(controller, filters.AuthorizationFilters);
AddControllerToFilterList
<IExceptionFilter>(controller, filters.ExceptionFilters);
return filters;
}

分别读取了IActionFilter,IAuthorizationFilter,IResultFilter,IExceptionFilter 属性标签,当然也包括Controller本身。

然后继续看InvokeAction执行的代码:

最先执行的是IAuthorizationFilter

   AuthorizationContext context = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, actionDescriptor);

其次是IActionFilter(Action也发生在这个位置)

   ActionExecutedContext context2 = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, actionDescriptor

仔细找找发现IResultFilter 被放在context2后面的这个方法里执行的

   this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, context2.Result);

  最后是IExceptionFilter

   ExceptionContext context3 = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, exception);

上面就是Filter与Action的执行顺序。以前鄙视人家变量这A1,A2,A3的,微软也这么干,我也不好说啥了(-_-|||)。

还剩下一个问题? 传给Action的参数是如何转换成对象的? 这个我还没有看到代码是怎么实现的。因为MVC源码,就不必再Refletor看了,明天下了源码去分析传给Action的参数是如何转变成对象的。

posted on 2011-06-27 01:51  小城岁月  阅读(22274)  评论(27编辑  收藏  举报

导航

面朝大海,春暖花开!