asp.net-mvc中使用IOC容器创建控制器实例

1.)在使用IOC之前,先谈谈什么是IOC?
IOC是Inversion of Control的缩写-“控制反转”。

解耦图.png

通过上图,由于引进了中间位置的第三方,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合的关系,所有的对象都由容器进行管理,这样也可以看出对象A获得依赖对象B的过程,由主动变成被动-(控制反转)

2.)如何通过IOC容器创建实例?
IOC容器是通过反射进行创建实例,而对IOC的具体实现的框架有多种,当然也可以自己封装一套自己的容器,而今天主要介绍的是Unity容器。
通过NuGet导入Unity包:


Unity包.png

创建一个Unity容器:
IUnityContainer unityContainer = new UnityContainer();
注册对象:
//IPhone-抽象
//AndroidPhone-具体实现
unityContainer.RegisterType<IPhone, AndroidPhone>();
获取对象的实例:
IPhone phone = unityContainer.Resolve<IPhone>();

3.)Unity生命周期
默认瞬时生命周期:每次返回都是一个新的对象。

container.RegisterType<AbstractPad, ApplePad>(new TransientLifetimeManager());
AbstractPad Pad1 = container.Resolve<AbstractPad>();
AbstractPad Pad2 = container.Resolve<AbstractPad>();
Console.WriteLine(object.ReferenceEquals(Pad1, Pad2));

单例生命周期:每次返回都是同一个对象。

container.RegisterType<AbstractPad, ApplePad>(new SingletonLifetimeManager());
AbstractPad pad1 = container.Resolve<AbstractPad>();
AbstractPad pad2 = container.Resolve<AbstractPad>();
Console.WriteLine(object.ReferenceEquals(pad1, pad2));

线程单例生命周期:同一个线程就只有一个实例,不同线程就是不同实例。

container.RegisterType<AbstractPad, ApplePad>(new PerThreadLifetimeManager());
AbstractPad pad1 = null;
AbstractPad pad2 = null;
AbstractPad pad3 = null;
Action act1 = new Action(() =>
{
    pad1 = container.Resolve<AbstractPad>();
    Console.WriteLine($"pad1由线程id={Thread.CurrentThread.ManagedThreadId}");
});
var result1 = act1.BeginInvoke(null, null);

Action act2 = new Action(() =>
{
    pad2 = container.Resolve<AbstractPad>();
    Console.WriteLine($"pad2由线程id={Thread.CurrentThread.ManagedThreadId}");
});
var result2 = act2.BeginInvoke(t =>
{
    pad3 = container.Resolve<AbstractPad>();
    Console.WriteLine($"pad3由线程id={Thread.CurrentThread.ManagedThreadId}");
    Console.WriteLine($"object.ReferenceEquals(pad2, pad3)={object.ReferenceEquals(pad2, pad3)}");
}, null);
act1.EndInvoke(result1);
act2.EndInvoke(result2);
Console.WriteLine($"object.ReferenceEquals(pad1, pad2)={object.ReferenceEquals(pad1, pad2)}");

4.)Unity通过配置文件进行注册
配置文件代码:

 <unity>
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
    <containers>
      <container name="testContainer1">
        <!--支持AOP-->
        <extension type="Interception"/>
        <register type="IOC.Interface.IPhone,IOC.Interface" mapTo="IOC.Service.ApplePhone, IOC.Service"/>
        <!--是dll名称,不是命名空间-->
        <!--接口多个实现别名获取-->
        <register type="IOC.Interface.IPhone,IOC.Interface" mapTo="IOC.Service.AndroidPhone, IOC.Service" name="Android">
          <!--别名--> 
          <interceptor type="InterfaceInterceptor"/>
          <interceptionBehavior type="Common.AOP.LogBeforeBehavior, Common"/>
          <interceptionBehavior type="Common.AOP.LogAfterBehavior, Common"/>
          <interceptionBehavior type="Common.AOP.ParameterCheckBehavior, Common"/>
          <lifetime type="transient" /> 
        </register>
        <register type="IOC.Interface.IMicrophone, IOC.Interface" mapTo="IOC.Service.Microphone, IOC.Service"/>
        <register type="IOC.Interface.IHeadphone, IOC.Interface" mapTo="IOC.Service.Headphone, IOC.Service"/>
        <register type="IOC.Interface.IPower, IOC.Interface" mapTo="IOC.Service.Power, IOC.Service"/>
        <register type="IOC.Interface.AbstractPad, IOC.Interface" mapTo="IOC.Service.ApplePad, IOC.Service"/>
        <register type="IOC.IDAL.IBaseDAL, IOC.IDAL" mapTo="IOC.DAL.BaseDAL, IOC.DAL"/>
        <register type="IOC.IBLL.IBaseBll, IOC.IBLL" mapTo="IOC.BLL.BaseBll, IOC.BLL">
          <constructor>
            <param name="baseDAL" type="IOC.IDAL.IBaseDAL, IOC.IDAL"  />
            <param name="id" type="System.Int32" value="3" />
          </constructor>
        </register>
        <register type="IOC.IDAL.IDBContext`1, IOC.IDAL" mapTo="IOC.DAL.DBContextDAL`1, IOC.DAL"/>
      </container>
    </containers>
  </unity>

前台创建实例:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");//找配置文件的路径
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
IUnityContainer container = new UnityContainer();
section.Configure(container, "testContainer1");
//创建实例
IPhone phone = container.Resolve<IPhone>("Android");

5.)基于Unity扩展AOP:AOP面向切面编程应用场景

在有了以上了解之后,在去通过IOC容器创建控制器实例便清晰了
有参控制器,通过容器创建并构造函数依赖注入

 public class ThirdController : Controller
{
          public IUserService _iUserService = null;
          public ICompanyService _iCompanyService = null;

          public ThirdController(IUserService userService, ICompanyService companyService)
          { 
                     _iUserService = userService;
                     _iCompanyService = companyService; 
           }
}

1.)重写“默认控制器工厂”

public class CustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
   {
        //要通过容器来创建控制器实例  得先得到容器
        //1. 获取容器,并将后期依赖进行注册
        IUnityContainer container = DIFactory.GetContainer();
        //2.通过容器创建控制器实例,根据实例类型,查找实例构造函数所需要的依赖项,
        //通过容器内的对象进行注入,若在容器内无法找到则无法实例该对象
        return (IController)container.Resolve(t: controllerType);       
    }
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        return base.CreateController(requestContext, controllerName);
    }
}

2.)替换“默认控制器工厂”
Global.asax

  //用自定义的控制器工厂替换掉MVC框架中默认的控制器工厂
  ControllerBuilder.Current.SetControllerFactory(new RichardControllerFactory());

经过上述的过程,

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容