1.)在使用IOC之前,先谈谈什么是IOC?
IOC是Inversion of Control的缩写-“控制反转”。
通过上图,由于引进了中间位置的第三方,也就是IOC容器,使得A、B、C、D这4个对象没有了耦合的关系,所有的对象都由容器进行管理,这样也可以看出对象A获得依赖对象B的过程,由主动变成被动-(控制反转)。
2.)如何通过IOC容器创建实例?
IOC容器是通过反射进行创建实例,而对IOC的具体实现的框架有多种,当然也可以自己封装一套自己的容器,而今天主要介绍的是Unity容器。
通过NuGet导入Unity包:
创建一个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());
经过上述的过程,