asp.net mvc源码分析-Controllerl篇 如何创建Controller实例

在上一篇文章asp.net mvc源码分析-路由篇 如何找到 IHttpHandler中最后提到了MvcHandler,来上我们看看它的定义

 public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState

它有几个比较重要的属性:

internal ControllerBuilder ControllerBuilder  ,ControllerBuilder 类主要负责创建IControllerFactory

public RequestContext RequestContext,RequestContext是对这次请求的HttpContext(httpContext类)和RouteData的包装

而它的BeginProcessRequest方法中有几句比较重要的代码:

IControllerFactory factory;
ProcessRequestInit(httpContext, out controller, out factory);
IAsyncController asyncController = controller as IAsyncController;

if (asyncController != null) {
}
else
{
  Action action = delegate {
                        try {
                            controller.Execute(RequestContext);
                        }
                        finally {
                            factory.ReleaseController(controller);
                        }
 return AsyncResultWrapper.BeginSynchronous(callback, state, action, _processRequestTag);
}

在这篇文章中我们主要关心ProcessRequestInit(httpContext, out controller, out factory);    如何创建controller

ProcessRequestInit方法大致如下:

  private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) {
            string controllerName = RequestContext.RouteData.GetRequiredString("controller");
            factory = ControllerBuilder.GetControllerFactory();
            controller = factory.CreateController(RequestContext, controllerName);

  }

         string controllerName = RequestContext.RouteData.GetRequiredString("controller");这句很简单获取Controller的名称,RouteData是当前路由数据,里面的key包括我们注册是的url格式  "{controller}/{action}/{id}",  和默认的defaults=new { controller = "Home", action = "Index", id = UrlParameter.Optional } 

现在大家知道为什么了我上一篇文章提到{controller}/{action}是必须得了吧。

现在让我们来看看ControllerBuilder的主要代码:

  由以上代码我们可以知道如果没有调用ControllerBuilder的SetControllerFactory方法那我们就用默认的DefaultControllerFactory,如果设置了我们就可以用我们自己ControllerFactory。如果项目有需要实现自己的ControllerFactory,那么我们可以Global.asax.cs的 protected void Application_Start()方法调用 ControllerBuilder.Current.SetControllerFactory(xxx); 

让我们来看看DefaultControllerFactory是怎么创建的:

  internal DefaultControllerFactory(IControllerActivator controllerActivator, IResolver<IControllerActivator> activatorResolver, IDependencyResolver dependencyResolver) {
            if (controllerActivator != null) {
                _controllerActivator = controllerActivator;
            }
            else {
                _activatorResolver = activatorResolver ?? new SingleServiceResolver<IControllerActivator>(
                    () => null,
                    new DefaultControllerActivator(dependencyResolver),
                    "DefaultControllerFactory contstructor"

                );
            }
        }

这里我们涉及到一个IControllerActivator接口,默认情况下用的是DefaultControllerActivator类,

现在我们已经得到了ControllerFactory,再看看它是怎么创建Controller的,说白了就是DefaultControllerFactory的CreateController方法

 public virtual IController CreateController(RequestContext requestContext, string controllerName) {
    。。
            Type controllerType = GetControllerType(requestContext, controllerName);
            IController controller = GetControllerInstance(requestContext, controllerType);

            return controller;
        }

默认我们是没有namespaces,而GetControllerType(requestContext, controllerName)主要是调用 GetControllerTypeWithinNamespaces(requestContext.RouteData.Route, controllerName, null /* namespaces */)

这里面主要涉及到一个ControllerTypeCache,它负责缓存当前程序中所有的Controller。

让我们看看ControllerTypeCache的主要方法吧

 List<Type> controllerTypes = TypeCacheUtil.GetFilteredTypesFromAssemblies(_typeCacheName, IsControllerType, buildManager);这句代码就是用来查询当前程序的类,这个类必须通过IsControllerType方法的验证(类是共有非抽象继承于IController且类名Controller结尾),而这个_cache是个Dictionary<string, ILookup<string, Type>>类型的数据。
现在我们已经得到了ControllerType,来看看 IController controller = GetControllerInstance(requestContext, controllerType);吧里面主要就一句
 ControllerActivator.Create(requestContext, controllerType);而ControllerActivator就是先前的DefaultControllerActivator,DefaultControllerActivator的代码如下:

 这里的_resolverThunk()来源于DependencyResolver.Current,
private static DependencyResolver _instance = new DependencyResolver();
        public static IDependencyResolver Current {
            get {
                return _instance.InnerCurrent;
            }
        }
 private IDependencyResolver _current = new DefaultDependencyResolver();
        public IDependencyResolver InnerCurrent {
            get {
                return _current;
            }
        }
所以真正创建controller是在DefaultDependencyResolver的GetService方法,核心代码   return Activator.CreateInstance(serviceType);
这篇文件扯得比较远,可见创建Controller是多么的麻烦啊。阅读源代码主要是让我们理解其逻辑,同时也让我们学习其开发的思想。
本文讲的这么多,在项目中最常用的就是ControllerBuilder.Current.SetControllerFactory(xxx);  只要大家理解了它就可以了。 

  

 

posted on   dz45693  阅读(2452)  评论(0编辑  收藏  举报

编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构

导航

< 2012年11月 >
28 29 30 31 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 1
2 3 4 5 6 7 8
点击右上角即可分享
微信分享提示