我们都知道ASP.NET首先是从Global.aspx中开始运行的, 在Application_Start()中添加路由映射后, 就由URLRouting组件创建IRouteHandler并执行, 在ASP.NET MVC默认情况下是MvcRouteHandler(关于自定义RouteHandler, 请参考其他的相关文章), 我们先看看MvcRouteHandler的源码:

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调用流程到此就结束了.

ASP.NET MVC运行机制源码剖析的更多相关文章

  1. Php5.6.15-fpm的运行机制源码剖析

    源码版本:Php5.6.15 源码目录:sapi/fpm/fpm 说明:源码的主要功能在上面直接注解 =============>>start<<=============== ...

  2. 【图解ASP.NET MVC运行机制理解-简易版】

    很多盆友咨询ASP.NET MVC的机制.网上也有好多.但是都是相当深奥.看的云里雾里的.我今天抽空,整理个简易版本.把处理流程走一遍. 当然,这个只是处理请求的一部分环节.百度的面试题“客户端从浏览 ...

  3. 响应式Asp.net MVC企业网站源码

    最近时间充裕,自己写了一个响应式MVC企业网站系统,用于回顾自己的MVC知识.网站源码后台和前台都采用响应式布局,可以适应不同的屏幕. 一.源码描述 响应式企业网站系统,前台和后台都采用了响应式布局, ...

  4. [解决]ASP.NET MVC 4/5 源码调试(source code debug)

    ========================ASP.NET MVC 4============================ ASP.NET MVC 4 source code download ...

  5. Struts2运行流程-源码剖析

    本文为原创,如需转载,请标明出处:http://www.cnblogs.com/gudu1/p/7726172.html 首先说一下查看这些框架源码的感受,每一次深入探究 Spring.Struts ...

  6. spark读取文件机制 源码剖析

    Spark数据分区调研 Spark以textFile方式读取文件源码 textFile方法位于 spark-core_2.11/org.apache.spark.api.java/JavaSparkC ...

  7. NET MVC运行机制

    [图解ASP.NET MVC运行机制理解-简易版]   很多盆友咨询ASP.NET MVC的机制.网上也有好多.但是都是相当深奥.看的云里雾里的.我今天抽空,整理个简易版本.把处理流程走一遍. 当然, ...

  8. 老李推荐:第5章5节《MonkeyRunner源码剖析》Monkey原理分析-启动运行: 获取系统服务引用

    老李推荐:第5章5节<MonkeyRunner源码剖析>Monkey原理分析-启动运行: 获取系统服务引用   上一节我们描述了monkey的命令处理入口函数run是如何调用optionP ...

  9. Flask核心机制--上下文源码剖析

    一.前言 了解过flask的python开发者想必都知道flask中核心机制莫过于上下文管理,当然学习flask如果不了解其中的处理流程,可能在很多问题上不能得到解决,当然我在写本篇文章之前也看到了很 ...

随机推荐

  1. PHP 类型判断和NULL,空值检查

    PHP是一种宽松类型的编程语言,在函数中对传入的参数值的“类型”以及”值是否为空或者NULL“进行检查是不可缺少的步骤. 类型检查 从PHP5开始,PHP允许对函数的参数进行类型约束,即可以约束参数的 ...

  2. MySQL 中隔离级别 RC 与 RR 的区别

    1. 数据库事务ACID特性 数据库事务的4个特性: 原子性(Atomic): 事务中的多个操作,不可分割,要么都成功,要么都失败: All or Nothing. 一致性(Consistency): ...

  3. Servlet/JSP-05 Cookie

    一. 问题? HTTP协议是一种无状态协议,服务器本身无法识别出哪些请求是同一个浏览器发出的,浏览器的每一次请求都是独立的.现实业务中服务器有时候需要识别来自同一个浏览器的一系列请求,例如购物车,登录 ...

  4. .NET笔记(一)

    物理路径 context.Server.MapPath() 获取DataTable的某个单元格的值 tb.Rows[i][j] 或 tb.Rows["某一行"]["某一列 ...

  5. 使用Spring MVC 实现 国际化

    使用Spring MVC 实现 国际化     博客分类: Spring   1. 版本 Spring 3.1   2. 配置 LocaleResolver     LocaleResolver 是指 ...

  6. react native windows开发环境搭建(二)

    上一篇中介绍了本地服务器端环境的安装,使用已经编译好的apk程序,设置ip地址,就可以看到welcome界面,并且可以对程序做出修改以及调试. 为了扩展和发布应用 还需要能编译loader程序,这里介 ...

  7. 烂泥:apache密码生成工具htpasswd的应用

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 1. htpasswd的作用与安装 2. htpasswd命令详解 3. htpasswd的实例 4. htpasswd的应用 一.htpasswd的作 ...

  8. 烂泥:SQL Server 2005数据库安装

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 为了能更好的利用服务器,所以打算把该业务进行迁移.因为该业务比较特殊,需要服务器上有相应的硬件支持,所以打算直接升级该服务器目前的操作系统.目前公司服务 ...

  9. CentOS 6.3下配置软RAID(Software RAID)

    一.RAID 简介 RAID 是英文Redundant Array of Independent Disks 的缩写,翻译成中文意思是“独立磁盘冗余阵列”,有时也简称磁盘阵列(Disk Array). ...

  10. C++ 笔记(二) —— 不要在构造和析构函数中调用虚函数

    ilocker:关注 Android 安全(新手) QQ: 2597294287 class Transaction { //所有交易的 base class public: Transaction( ...