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作为参数添加到构造函数的参数当中;

原创粉丝点击