【转】ASP.NET MVC学习笔记-MVC运行机制之源码剖析

学习ASP.NET MVC已经有段时间了,以前都是断断续续的了解了下, 对于ASP.NET MVC路由及运行机制一直不是很了解, 在网络上找了好多资料无非都是讲解了下如何添加ASP.NET MVC路由及创建自定义视图引挚等. 因此最近这几天, 下载了ASP.NET MVC源码好好研究了一翻, 将其运行机制记录下来, 一来整理下自己的理解思路, 加强自己的理解, 二来也希望对学习ASP.NET的后来者有所帮助, 文中都是自我理解, 有错误之处望高手能帮忙纠正之!!

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

view plaincopy to clipboardprint?
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  

    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)实例, 源码如下:

view plaincopy to clipboardprint?
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);  
    }  

        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类部分代码:

view plaincopy to clipboardprint?
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;  
    }  

    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源码就知道了.
view plaincopy to clipboardprint?
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;  

        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 */);那我们也看看它做了些什么动作.
view plaincopy to clipboardprint?
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);  
   ...  
    } 
        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实现如下:
view plaincopy to clipboardprint?
protected virtual void Execute(RequestContext requestContext) {  
    if (requestContext == null) {  
        throw new ArgumentNullException("requestContext");  
    }  
    Initialize(requestContext);  
    ExecuteCore();  

        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类实现了此方法,实现如下:

view plaincopy to clipboardprint?
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);  
    }  

        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的呢? 还是从源码入手:
view plaincopy to clipboardprint?
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;  

        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方法:
view plaincopy to clipboardprint?
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);  

        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列表中去:
view plaincopy to clipboardprint?
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;  

        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代码如下:
view plaincopy to clipboardprint?
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;  

        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对象返回:
view plaincopy to clipboardprint?
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  
    };  

        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.
view plaincopy to clipboardprint?
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);  
    }  

        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中的实现如下:    

view plaincopy to clipboardprint?
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));  
      } 
     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中的属性:

view plaincopy to clipboardprint?
public ViewEngineCollection ViewEngineCollection {  
    get {  
        return _viewEngineCollection ?? ViewEngines.Engines;  
    }  
    set {  
        _viewEngineCollection = value;  
    }  

        public ViewEngineCollection ViewEngineCollection {
            get {
                return _viewEngineCollection ?? ViewEngines.Engines;
            }
            set {
                _viewEngineCollection = value;
            }
        }

默认情况下是ViewEngines的静态属性Engines, 所以在自定义视图引挚时, 我们一般都会在Globol.cs中的Application_Start()中将自己定义的视图引挚添加到ViewEngines.Engines中去, ASP.NET MVC默认情况下就有new WebFormViewEngine().

view plaincopy to clipboardprint?
public static class ViewEngines {  
    private readonly static ViewEngineCollection _engines = new ViewEngineCollection {  
        new WebFormViewEngine()   
    };  
    public static ViewEngineCollection Engines {  
        get {  
            return _engines;  
        }  
    }  

    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实现:
view plaincopy to clipboardprint?
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);  

        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实现如下:
view plaincopy to clipboardprint?
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) {  
     return new WebFormView(viewPath, masterPath);  

       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对象并输出,关键代码如下:
view plaincopy to clipboardprint?
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);  
        } 
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调用流程到此就结束了.

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/study_live/archive/2009/11/25/4871745.aspx

转载于:https://www.cnblogs.com/shong/archive/2010/08/14/1799691.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值