1、配置文件
说明:此处有两个容器的节点,用来分别初始化两个容器,可以应对需要注入两个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>

2、初始化容器
说明:创建了一个枚举,用来对应配置文件中的两个节点,然后通过扩展方法获取到枚举值在配置文件中的节点名称,用来分别初始化不同的容器。
代码:
容器的工厂:

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(); } } }

3、接口和实现类的代码
接口:

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); } }

4、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; } } }

5、测试代码

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(); }

6、总结 AOP扩展的进入顺序是根据配置文件从上到下进入,业务逻辑与拓展逻辑的执行顺序是根据getNext().Invoke(input, getNext)代码的位置决定。