MVC学习笔记-理解ASP.NET MVC的DependencyResolver组件
来源:互联网 发布:xmind 破解版 linux 编辑:程序博客网 时间:2024/06/04 18:46
DependencyResolver是MVC中一个重要的组件,从名字可以看出,它负责依赖对象的解析,可以说它是MVC框架内部使用的一个IOC容 器。MVC内部很多对象的创建都是通过它完成的,或许我们平时没有直接用到它,但是如果你在使用unity、autofac,或者在看一些开源项目时,总 会看到它的身影。接下来就让我们看一下这个组件是如何工作的。
二、通过Controller的激活理解DependencyResolver的工作过程
这里先插一个题外话,经常会有面试问:asp.net 几个核心对象是什么?一般人都会回答:Server、Request、Response、Session、Cookie这些。但我的回答会是 HttpApplication、HttpHandler和HttpModule,这才是管道模型中的核心类型,整个asp.net的处理流程和可扩展性 也都是建立在这几个对象上的。
回到主题,ASP.NET的请求都是交给HttpHandler处理的,对于MVC来说,是交给一个MvcHandler,它负责激活以及创建Controller
protected internal virtual IAsyncResult BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, object state){ IController controller; IControllerFactory factory; ProcessRequestInit(httpContext, out controller, out factory); //其它操作 //调用 controller.Execute方法}
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory){ //获取当前请求上下文实例 HttpContext currentContext = HttpContext.Current; //从路由获取本期请求的Controller名称 string controllerName = RequestContext.RouteData.GetRequiredString("controller"); //通过ControllerBuilder获取ControllerFactory,默认就是DefaultControllerFactory factory = ControllerBuilder.GetControllerFactory(); //通过ControllerFactory获取Controller对象,创建控制器实例 controller = factory.CreateController(RequestContext, controllerName);}
ControllerFactory故名思议就是用于创建Controller的,我们也可以自己实现IControllerFactory, 参与Controller的激活过程,具体是在全局调用ControllerBuilder.Current.SetControllerFactory 方法。我们这里主要关注的是Controller的激活过程,实际上它们的创建过程是相似的。默认使用的ControllerFactory是DefaultControllerFactory。DefaultControllerFactory的CreateController方法如下:
public virtual IController CreateController(RequestContext requestContext, string controllerName){ //获取Controller类型 Type controllerType = GetControllerType(requestContext, controllerName); IController controller = GetControllerInstance(requestContext, controllerType); return controller;}protected internal virtual IController GetControllerInstance(RequestContext requestContext, Type controllerType){ return =this.ControllerActivator.Create(requestContext, controllerType);}
CreateController通过GetControllerType方法来获取controllerName指定的控制器类型名称,并通过
GetControllerInstance方法中一个this.ControllerActivator.Create方法通过依赖注入的方式来创建当前controllerType指定的IController对象(默认情况下ControllerActivator将调用DefaultControllerActivator控制激活器),DefaultControllerActivator 源代码如下
private class DefaultControllerActivator : IControllerActivator{ // Fields private Func<IDependencyResolver> _resolverThunk; // Methods public DefaultControllerActivator() : this(null) { } public DefaultControllerActivator(IDependencyResolver resolver) { Func<IDependencyResolver> func = null; if (resolver == null) { this._resolverThunk = () => DependencyResolver.Current; } else { if (func == null) { func = () => resolver; } this._resolverThunk = func; } } public IController Create(RequestContext requestContext, Type controllerType) { IController controller; try { controller = (IController) (this._resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType)); } catch (Exception exception) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, MvcResources.DefaultControllerFactory_ErrorCreatingController, new object[] { controllerType }), exception); } return controller; }}
DefaultControllerActivator包含有两个构造函数,如果构造函数参数中IDependencyResolver实例为空(即没有使用自定义DI容器),则this._resolverThunk默认将使用DependencyResolver
组件中的DI容器
注意:这里的resolverThunk是指一个获取IDependencyResolver对象的委托,获取的是实现了IDependencyResolver接口的实例对象,但是System.Web.MVC.DependencyResolver组件并没有实现IDependencyResolver接口,只是用于对DI容器进行装载,所以需要通过调用DependencyResolver.current属性加载DI容器
//DependencyResolver构造函数public DependencyResolver(){ this.InnerSetResolver((IDependencyResolver) new DefaultDependencyResolver());}//InnerSetResolver方法的具体实现public void InnerSetResolver(IDependencyResolver resolver){ if (resolver == null) { throw new ArgumentNullException("resolver"); } this._current = resolver; this._currentCache = new CacheDependencyResolver(this._current);}
如果我们查看DependencyResolver类的构造函数可以发现,在DependencyResolver将默认启用MVC框架中的DI容器并赋值给_current属性(即DefaultDependencyResolver),但是我们也可以通过SetResolver方法在全局中创建新的DI容器对DefaultDependencyResolver进行替换,例如:我们创建AutofacDependencyResolverDI容器对DefaultDependencyResolver
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));//SetResolver内部中调用InnerSetResolver方法添加DI容器,从而实现对DefaultDependencyResolver的替换public static void SetResolver(IDependencyResolver resolver){ _instance.InnerSetResolver(resolver);}
同时在Create方法中,首先将通过GetService(controllerType)方法来获取controllerType指定的对象类型,如果获取的类型为空,则将直接通过Activator.CreateInstance方法来创建controllerType对象实例。
result = (IController)(this._resolverThunk().GetService(controllerType) ?? Activator.CreateInstance(controllerType));
我们返回到DefaultDependencyResolver类型(默认的DI容器)以及AutofacDependencyResolver类型中,来看一下GetService方法的具体实现;
public object GetService(Type serviceType){ if (serviceType.IsInterface || serviceType.IsAbstract) { return null; } try { return Activator.CreateInstance(serviceType); } catch { return null; }}
添加依赖注入即可以实现单一添加,也可以实现批量添加,例如:
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerHttpRequest();builder.RegisterAssemblyTypes(typeof(CartRespository).Assembly).Where(t => t.Name.EndsWith("Respository")).AsImplementedInterfaces();
builder.RegisterType().As()方法为UnitOfWork类型添加了依赖注入,然后通过DependencyResolver.GetService方法获取UnitOfWork类型的实例对象,在创建实例对象的过程中,DependencyResolver将对UnitOfWork的构造函数进行扫描,如果UnitOfWork的构造函数中包含具有依赖关系的参数,则将自动为该参数创建:
通过依赖注入来创建实例的方式主要包含三种:(1)构造器注入;(2)属性注入;(3)接口注入。所以需要实现完全的关注分离,我们可以将Controller对象构造函数进行重构,将需要通过依赖注入创建的interface作为参数添加到构造函数的参数当中;
- MVC学习笔记-理解ASP.NET MVC的DependencyResolver组件
- 理解ASP.NET MVC的DependencyResolver组件 (依赖注入)
- Asp.net MVC 学习笔记
- ASP.NET MVC学习笔记
- asp.net MVC学习笔记
- ASP.NET MVC 学习笔记
- ASP.NET MVC学习笔记
- ASP.NET MVC学习笔记
- ASP.net mvc学习笔记
- Asp.net MVC 学习笔记
- 学习ASP.NET MVC(二) 识别URL的Routing组件
- MVC学习笔记1---MVC的理解
- Asp.Net MVC 学习笔记 - ASP.NET MVC 3的概述
- ASP.NET MVC 笔记
- ASP.NET MVC笔记
- ASP.NET MVC 各种上下文的理解
- ASP.NET MVC 1.0学习笔记
- asp.net mvc 2.0学习笔记
- Win 10 操作
- 如何解决maven项目自动下载jar包时下载的是空jar包文件夹以及某些jar包下载不了
- 算法1.1 下压(LIFO)栈 (能够动态调整数组大小的实现)
- DA14580 蓝牙低功耗莫模式IO口不能保持的解决办法
- 基础3
- MVC学习笔记-理解ASP.NET MVC的DependencyResolver组件
- 树莓派更新资源出现failed to fetch问题
- dp部分总结(单调队列,四边形优化,斜率优化,树形dp)
- 欧罗巴巅峰之战,尤文VS皇马谁终执牛耳?
- [bzoj1927][SDOI2010] 星际竞速 费用流
- HTTP协议详解(真的很经典)
- linux下select和epoll函数总结
- centos7安装配置mysql数据库
- Java之通讯录系统