zoukankan      html  css  js  c++  java
  • ASP.NET MVC运行机制源码剖析

    我们都知道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调用流程到此就结束了.
  • 相关阅读:
    jQuery动画速成
    elementui更改导航栏样式
    Python反射
    Linux基础--基本命令
    Linux基础--简介
    DRF
    Socket与Websocket初识
    五星宏辉游戏项目小结
    Redis详解(8)--redis-cluster
    Redis详解(7)--主从复制
  • 原文地址:https://www.cnblogs.com/zhyj/p/3444035.html
Copyright © 2011-2022 走看看