Lind.DDD.IoC依賴注入與面向方面的實現
阿新 • • 發佈:2018-12-30
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 privatestatic 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>View Code
非常感謝各位的閱讀!