一、配置文件
說明:此處有兩個容器的節點,用來分別初始化兩個容器,能夠應對須要注入兩個dbContext的狀況。
代碼:
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity>
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers>
<container name="yydyoaSection">
<extension type="Interception"/>
<register type="Study.Unity.Interface.IDoWork,Study.Unity" mapTo=" Study.Unity.Service.StudentDoWork,Study.Unity">
<interceptor type="InterfaceInterceptor"/>
<interceptionBehavior type="Study.Unity.Aop.ParameterCheckBehavior,Study.Unity"/>
<interceptionBehavior type="Study.Unity.Aop.CachingBehavior,Study.Unity"/>
<interceptionBehavior type="Study.Unity.Aop.ExpessionBehavior,Study.Unity"/>
<interceptionBehavior type="Study.Unity.Aop.LogBeforeBehavior,Study.Unity"/>
</register>
</container>
<container name="managerSection">
<extension type="Interception"/>
<register type="Study.Unity.Interface.IDoWork,Study.Unity" mapTo=" Study.Unity.Service.TeacherDoWork,Study.Unity">
<interceptor type="InterfaceInterceptor"/>
</register>
</container>
</containers>
</unity>
</configuration>緩存
二、初始化容器
說明:建立了一個枚舉,用來對應配置文件中的兩個節點,而後經過擴展方法獲取到枚舉值在配置文件中的節點名稱,用來分別初始化不一樣的容器。
代碼:
容器的工廠:app
public class DIFactory { private static readonly object _SyncHelper = new object(); private static volatile Dictionary<EnContainer, IUnityContainer> _UnityContainerDictionary = new Dictionary<EnContainer, IUnityContainer>(); public static IUnityContainer GetContainer(EnContainer enContainer) { if (!_UnityContainerDictionary.ContainsKey(enContainer)) { lock (_SyncHelper) { if (!_UnityContainerDictionary.ContainsKey(enContainer)) { //配置UnityContainer IUnityContainer container = new UnityContainer(); ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config"); Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); string strSection = enContainer.Speccn(); configSection.Configure(container, strSection); _UnityContainerDictionary.Add(enContainer, container); } } } return _UnityContainerDictionary[enContainer]; } }
枚舉:
public enum EnContainer { [Speccn("yydyoaSection")] YYDYOA = 1, [Speccn("managerSection")] MANAGER = 2 }
特性:
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = true)] public class SpeccnAttribute : Attribute { private string Speccn { get; set; } public SpeccnAttribute(string speccn) { this.Speccn = speccn; } public string GetSpeccn() { return this.Speccn; } }
擴展方法:
public static class EnumExtend { public static string Speccn(this Enum enContainer) { Type type = enContainer.GetType(); FieldInfo field = type.GetField(enContainer.ToString()); if (field.IsDefined(typeof(SpeccnAttribute), true)) { SpeccnAttribute speccnAttribute = (SpeccnAttribute)field.GetCustomAttribute(typeof(SpeccnAttribute)); return speccnAttribute.GetSpeccn(); } else { return enContainer.ToString(); } } }
三、接口和實現類的代碼
接口:ide
public interface IDoWork { string Show(string arg); }
實現類:
public class StudentDoWork : IDoWork { public string Show(string arg) { Console.WriteLine($"{this.GetType().Name}_DoWork Before"); Console.WriteLine($"{this.GetType().Name}_DoWork After"); return nameof(StudentDoWork); } } public class TeacherDoWork : IDoWork { public string Show(string arg) { Console.WriteLine($"{this.GetType().Name}_DoWork"); return nameof(TeacherDoWork); } }
四、AOP擴展類的代碼: 參數檢查:
public class ParameterCheckBehavior : IInterceptionBehavior { public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("ParameterCheckBehavior"); if (input.Inputs[0].ToString().Length < 10)//能夠過濾一下敏感詞 { //返回一個異常 return input.CreateExceptionMethodReturn(new Exception("密碼長度不能小於10位")); } else { Console.WriteLine("參數檢測無誤"); return getNext().Invoke(input, getNext); } } }
日誌:
public class LogBeforeBehavior : IInterceptionBehavior { public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("LogBehavior before"); IMethodReturn method = getNext()(input, getNext); Console.WriteLine("LogBehavior after"); return method; } }
異常:
public class ExpessionBehavior : IInterceptionBehavior { public bool WillExecute => true; public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { Console.WriteLine("ExpessionBehavior before"); IMethodReturn method = getNext()(input, getNext); if (method.Exception != null) Console.WriteLine($"異常:{method.Exception.Message}"); Console.WriteLine("ExpessionBehavior after"); return method; } }
緩存:
public class CachingBehavior : IInterceptionBehavior { public IEnumerable<Type> GetRequiredInterfaces() { return Type.EmptyTypes; } private static Dictionary<string, object> CachingBehaviorDictionary = new Dictionary<string, object>(); public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext) { string key = $"{input.MethodBase.Name}_{Newtonsoft.Json.JsonConvert.SerializeObject(input.Inputs)}"; if (CachingBehaviorDictionary.ContainsKey(key)) { return input.CreateMethodReturn(CachingBehaviorDictionary[key]); } else { IMethodReturn result = getNext().Invoke(input, getNext); if (result.ReturnValue != null) { CachingBehaviorDictionary.Add(key, result.ReturnValue); Console.WriteLine("CachingBehavior"); } return result; } } public bool WillExecute { get { return true; } } }
五、測試代碼
static void Main(string[] args) { IUnityContainer yydyoaContainer = DIFactory.GetContainer(EnContainer.YYDYOA); IDoWork doWork = yydyoaContainer.Resolve<IDoWork>(); doWork.Show("12345678901234"); yydyoaContainer = DIFactory.GetContainer(EnContainer.MANAGER); doWork = yydyoaContainer.Resolve<IDoWork>(); doWork.Show("123"); Console.ReadKey(); }
六、總結 AOP擴展的進入順序是根據配置文件從上到下進入,業務邏輯與拓展邏輯的執行順序是根據getNext().Invoke(input, getNext)代碼的位置決定。