IoC是解耦的灵魂,很难想像一个框架中没有IoC会变成什么样子,Lind.DDD里的IoC是通过Unity实现的,由依赖注入(unity)和方法拦截组成(Interception),依赖注入可以通过事前定义好的实现方式去动态建立某个接口的实例,例如,在仓储接口IRepository里,你可以在配置文件中定义它由EF实现,也可以让它由Mongodb实现,而表现出来的结果就是数据的持久化方式的不同。
模块的结构
服务定位器ServiceLocator
服务定位器可以帮助我们在不引用程序集的情况下,自动将它进行反射,这对于某些扩展注入的场合,非常有用,也是通过单例模式实现的。
/// <summary> /// Represents the Service Locator. /// </summary> public sealed class ServiceLocator : IServiceProvider { #region Private Fields private readonly IUnityContainer _container; #endregion #region Private Static Fields private static readonly ServiceLocator instance = new ServiceLocator(); #endregion #region Ctor /// <summary> /// Initializes a new instance of ServiceLocator class. /// </summary> private ServiceLocator() { UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); if (section == null) { var unityConfig = System.AppDomain.CurrentDomain.BaseDirectory + @"IoC.config"; var fileMap = new ExeConfigurationFileMap() { ExeConfigFilename = unityConfig }; var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); section = (UnityConfigurationSection)configuration.GetSection("unity"); } if (section == null) throw new ArgumentException("请配置unity节点..."); _container = new UnityContainer(); #region 装载config中的类型 section.Configure(_container); #endregion #region 注册动态类型 LoadDynamicType(_container); #endregion } #endregion #region Public Static Properties /// <summary> /// Gets the singleton instance of the ServiceLocator class. /// </summary> public static ServiceLocator Instance { get { return instance; } } #endregion #region Private Methods /// <summary> /// 装载一批动态的类型 /// Author:zhangzhanling /// Date:2015-04-03 /// </summary> private void LoadDynamicType(IUnityContainer _container) { //unity动态类型注入,各个程序集用,分开,支持*通配符号 string unityDynamicAssembly = System.Configuration.ConfigurationManager.AppSettings["unityDynamicAssembly"]; //是否同时启动数据集缓存策略 string unityCachingDoing = System.Configuration.ConfigurationManager.AppSettings["unityCachingDoing"] ; InjectionMember[] injectionMembers = new InjectionMember[] { }; if (unityCachingDoing == "1") { injectionMembers = new InjectionMember[] { new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<CachingBehavior>() }; } if (!string.IsNullOrWhiteSpace(unityDynamicAssembly)) { Array.ForEach(unityDynamicAssembly.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries), dllName => { var baseDir = AppDomain.CurrentDomain.BaseDirectory; if (System.Web.HttpContext.Current != null) { baseDir += "bin"; } var files = Directory.GetFiles(baseDir, dllName); var iTypes = new List<Type>(); foreach (var file in files) { var interfaceASM = Assembly.LoadFrom(Path.Combine(baseDir, file)); var types = from t in interfaceASM.GetTypes() where !string.IsNullOrWhiteSpace(t.Namespace) select t; foreach (var type in types) { if (type.GetInterfaces() != null && type.GetInterfaces().Any()) foreach (var father in type.GetInterfaces()) { _container.RegisterType(father , type , injectionMembers); } } } }); } } private IEnumerable<ParameterOverride> GetParameterOverrides(object overridedArguments) { List<ParameterOverride> overrides = new List<ParameterOverride>(); Type argumentsType = overridedArguments.GetType(); argumentsType.GetProperties(BindingFlags.Public | BindingFlags.Instance) .ToList() .ForEach(property => { var propertyValue = property.GetValue(overridedArguments, null); var propertyName = property.Name; overrides.Add(new ParameterOverride(propertyName, propertyValue)); }); return overrides; } #endregion #region Public Methods /// <summary> /// Gets the service instance with the given type. /// </summary> /// <typeparam name="T">The type of the service.</typeparam> /// <returns>The service instance.</returns> public T GetService<T>() { return _container.Resolve<T>(); } /// <summary> /// Gets the service instance with the given type by using the overrided arguments. /// </summary> /// <typeparam name="T">The type of the service.</typeparam> /// <param name="overridedArguments">The overrided arguments.</param> /// <returns>The service instance.</returns> public T GetService<T>(object overridedArguments) { var overrides = GetParameterOverrides(overridedArguments); return _container.Resolve<T>(overrides.ToArray()); } /// <summary> /// Gets the service instance with the given type by using the overrided arguments. /// </summary> /// <param name="serviceType">The type of the service.</param> /// <param name="overridedArguments">The overrided arguments.</param> /// <returns>The service instance.</returns> public object GetService(Type serviceType, object overridedArguments) { var overrides = GetParameterOverrides(overridedArguments); return _container.Resolve(serviceType, overrides.ToArray()); } #endregion #region IServiceProvider Members /// <summary> /// Gets the service instance with the given type. /// </summary> /// <param name="serviceType">The type of the service.</param> /// <returns>The service instance.</returns> public object GetService(Type serviceType) { return _container.Resolve(serviceType); } #endregion }
Interception方法拦截
这是AOP面向方面编程里的一个概念,它在方法进行前或者后,对它进行拦截,并注入新的业务逻辑,这种方法一般是接口方法和虚方法,为了方便大家使用,大家抽象了一个基类
/// <summary> /// 拦截器抽象基类 /// 实现拦截器的项目需要继承此类,只引用Microsoft.Practices.Unity.Interception.dll程序集 /// </summary> public abstract class InterceptionBase : IInterceptionBehavior { /// <summary> /// 获取当前行为需要拦截的对象类型接口。 /// </summary> /// <returns></returns> public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } /// <summary> ///通过实现此方法来拦截调用并执行所需的拦截行为。 /// </summary> /// <param name="input">调用拦截目标时的输入信息</param> /// <param name="getNext">通过行为链来获取下一个拦截行为的委托</param> /// <returns>从拦截目标获得的返回信息</returns> public abstract IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext); /// <summary> /// 获取一个<see cref="Boolean"/>值,该值表示当前拦截行为被调用时,是否真的需要执行拦截动作 /// </summary> public bool WillExecute { get { return true; } } }
下面是一个异常拦截器的实现
/// <summary> /// 拦截器实例,具体拦截器可以自己去建立项目来实现,需要实现IInterceptionBehavior接口 /// 表示用于异常日志记录的拦截行为。 /// </summary> public class ExceptionLoggingBehavior : InterceptionBase { /// <summary> /// 通过实现此方法来拦截调用并执行所需的拦截行为。 /// </summary> /// <param name="input">调用拦截目标时的输入信息。</param> /// <param name="getNext">通过行为链来获取下一个拦截行为的委托。</param> /// <returns>从拦截目标获得的返回信息。</returns> public override IMethodReturn Invoke( IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { //方法执行前 var methodReturn = getNext().Invoke(input, getNext);//原方法被执行 //方法执行后 if (methodReturn.Exception != null) { Console.WriteLine(methodReturn.Exception.Message); Logger.LoggerFactory.Instance.Logger_Error(methodReturn.Exception); } return methodReturn; } }
下面是IOC所需要的配置
<configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" /> </configSections> <!--BEGIN: Unity--> <unity> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" /> <container> <extension type="Interception" /> <!--被拦截的类型--> <register type="Lind.DDD.Test.AOP,Lind.DDD.Test" mapTo="Lind.DDD.Test.AOP,Lind.DDD.Test"> <interceptor type="VirtualMethodInterceptor"/> <!--InterfaceInterceptor,VirtualMethodInterceptor,TransparentProxyInterceptor,这种方法要求被拦截的类继承MarshalByRefObject--> <interceptionBehavior type="Lind.DDD.IoC.Interception.ExceptionLoggingBehavior,Lind.DDD" /> <!--拦截行为--> </register> </container> </unity> </configuration>
非常感谢各位的阅读!