一.   使用Unity的AOP实现

a)         整体项目截图:

b) 添加Unity的Nuget包, 直接使用最新版就行, 需要添加两个 Unity 和 Unity.Interception (这个是为AOP做的一个扩展)

c)    AOP配置文件, 详细注释(CfgFiles\Unity.Config)

 <!--这是一个标准Unity配置文件的格式-->

 <configuration> <!--根节点名称-->
<configSections>
<!--name容器的名称 type 表示如何查找节点, 这是固定写法-->
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration"/>
</configSections>
<unity>
<!--下面一行是固定写法, 用这个写法来支持AOP-->
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Unity.Interception.Configuration"/>
<containers><!--定义一组容器-->
<container name="aopContainer">
<!--定义一个容器; 表示在IUserProcessor这个接口下所有的方法都给他增加, 这个容器(aopContainer)内所包含的方法-->
<extension type="Interception"/>
<!--这里使用Interception类型的扩展; 其实在Unity中有三种类型来处理这件事; 这种是属于实现接口的方法, 还有一种是继承父类; 第三种是使用Virtual虚方法的形式, 使用虚方法有点类似于CastleProxyAOP这个代理-->
<!--把接口映射到具体的实现类; 也就是说告诉容器如果遇到了MyAOP.UnityWay.IUserProcessor这个抽象, 就使用MyAOP.UnityWay.UserProcessor来帮我们实例化-->
<!--MyAOP.UnityWay.IUserProcessor完整的接口名称, MyAOP是程序所在的dll名称, 程序集的名称(当然在这里是当前exe文件的名称-->
<!--MyAOP.UnityWay.UserProcessor具体的实现类, MyAOP和上面的解释一样-->
<!--MyAOP是程序集的名称-->
<!-- register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP" 这一句整体的意思就是告诉容器, 如果遇到IUserProcessor这个抽象, 就使用UserProcessor类来帮我进行初始化一个具体的实例出来-->
<register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP">
<!--Unity中的AOP有三种模式, 第一种必须继承MarshalByRefObject这个父类的AOP
第二种必须是虚方法的AOP
第三种就是下面写的接口形式的 InterfaceInterceptor 一般都用这种接口形式的:
表示只要是接口下的所有方法, 都会被增加上下面的方法
-->
<interceptor type="InterfaceInterceptor"/> <!--AOP支持的模式; 推荐使用这种接口模式的-->
<!--下面这五个表示 在IUserProcessor接口中的所有方法, 都拥有下面方法的扩展--> <!--异常处理的; 注意如果你想全局处理异常, 则应该把异常处理的Behavior放到最顶层, 否则在Unity中自己抛出的异常则会抓不到-->
<interceptionBehavior type="MyAOP.UnityWay.ExceptionLoggingBehavior, MyAOP"/>
<!--缓存的behavior; 注意缓存的Behavior也应该放在记录日志之前; 需要注意的是, 如果被缓存命中了, 那么后面的AOP也不会执行的-->
<interceptionBehavior type="MyAOP.UnityWay.CachingBehavior, MyAOP"/>
<!--方法执行前写日志-->
<interceptionBehavior type="MyAOP.UnityWay.LogBeforeBehavior, MyAOP"/>
<!--参数检查-->
<interceptionBehavior type="MyAOP.UnityWay.ParameterCheckBehavior, MyAOP"/>
<!--方法执行后做的事情-->
<interceptionBehavior type="MyAOP.UnityWay.LogAfterBehavior, MyAOP"/>
</register>
</container>
</containers>
</unity>
</configuration>

d)  Model代码:

 public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Password { get; set; }
}

e)  IuserProcessor代码:

 public interface IUserProcessor
{
void RegUser(User user);
User GetUser(User user);
}

f)  UserProcessor代码:

  public class UserProcessor : IUserProcessor
{
public void RegUser(User user)
{
Console.WriteLine("用户已注册。");
//throw new Exception("11");
}
[Obsolete]
public User GetUser(User user)
{
return user;
}
}

g) LogBeforeBehavior代码(在方法执行之前写日志):

 /// <summary>
/// 1. 标准的通过AOP写日志的功能, 必须实现IInterceptionBehavior; 这个接口来自于Unity容器
/// </summary>
public class LogBeforeBehavior : IInterceptionBehavior
{
/// <summary>
/// 3. 此方法为固定写法
/// </summary>
/// <returns></returns>
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} /// <summary>
/// 4. 关键方法
/// </summary>
/// <param name="input"></param>
/// <param name="getNext"></param>
/// <returns></returns>
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("LogBeforeBehavior");
//5. 如果有的方法想用, 有的方法不想被AOP, 则可以在这里做切断 //这里可以将某个方法打上特性,然后获取MemberInfo中的特性信息, 以此来判断哪个
//方法需要AOP切入,哪些方法不需要AOP切入
Console.WriteLine(input.MethodBase.Name);
// Console.WriteLine( input.MethodBase.GetCustomAttributes(true)[0].ToString() );
foreach (var item in input.Inputs) //input中包含了所有的参数信息
{
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
//反射&序列化获取更多信息
}
// Unity.Interception.InterceptionBehaviors.InvokeInterceptionBehaviorDelegate gn = getNext();
// return getNext()(input, getNext);//注意这种写法也是可以的; 这种写法的意思就是getNext()方法返回了一个委托, 然后委托又被调用了
return getNext().Invoke(input, getNext);//4. 固定写法 // return null;
//return gn.Invoke(input, getNext);
//getNext()表示执行完当前的方法之后, 去执行原始方法; 但是注意的是, getNext()中可能有多个方法
} /// <summary>
/// 2. 固定写法
/// </summary>
public bool WillExecute
{
get { return true; }
}
}

h)  LogAfterBehavior代码(方法执行之后写日志):

 //IInterceptionBehavior来自于AOP容器中      Unity.Interception.InterceptionBehaviors;
public class LogAfterBehavior : 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 IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
//getNext()(input, getNext); 关键点; 如果业务代码写在这句话之前, 那么就会先执行业务代码, 再执行配置文件中配置的实例代码; 反之同理 IMethodReturn methodReturn = getNext().Invoke(input, getNext);//执行后面的全部动作
//原始方法执行后 Console.WriteLine("LogAfterBehavior");
Console.WriteLine(input.MethodBase.Name);
foreach (var item in input.Inputs)
{
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(item));
//反射&序列化获取更多信息
}
Console.WriteLine("LogAfterBehavior" + methodReturn.ReturnValue);
return methodReturn;
} /// <summary>
/// 固定写法
/// </summary>
public bool WillExecute
{
get { return true; }
}
}

i)  ParameterCheckBehavior代码(在方法执行之前进行参数校验):

 /// <summary>
/// 参数检查
/// </summary>
public class ParameterCheckBehavior : IInterceptionBehavior
{
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("ParameterCheckBehavior");
User user = input.Inputs[] as User;//可以不写死类型,反射+特性完成数据有效性监测
if (user.Password.Length < )//可以过滤一下敏感词
{
//返回一个异常
return input.CreateExceptionMethodReturn(new Exception("密码长度不能小于10位"));
//注意只要抛出异常, 那么后面的都不会再执行了, 在这里也就是说后的 logafterbehavior是不会再执行了
//throw new Exception("密码长度不能小于10位");
}
else
{
Console.WriteLine("参数检测无误");
return getNext().Invoke(input, getNext);
}
} public bool WillExecute
{
get { return true; }
}
}

j) ExceptionLoggingBehavior代码(异常处理):

 /// <summary>
/// 异常处理
/// </summary>
public class ExceptionLoggingBehavior : IInterceptionBehavior
{
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
} public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn methodReturn = getNext()(input, getNext); Console.WriteLine("ExceptionLoggingBehavior");
if (methodReturn.Exception == null) //检查methodReturn中是否有异常
{
Console.WriteLine("无异常");
}
else
{
Console.WriteLine($"异常:{methodReturn.Exception.Message}");
}
return methodReturn;
} public bool WillExecute
{
get { return true; }
}
}

k)  CachingBehavior代码(缓存处理):

 /// <summary>
/// 缓存AOP
/// </summary>
public class CachingBehavior : IInterceptionBehavior
{
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
/// <summary>
/// 定义缓存字典
/// </summary>
private static Dictionary<string, object> CachingBehaviorDictionary = new Dictionary<string, object>(); public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
Console.WriteLine("CachingBehavior");
//把方法的名称和所有的参数列表全部标识为key , 然后放到字典里面;
string key = $"{input.MethodBase.Name}_{Newtonsoft.Json.JsonConvert.SerializeObject(input.Inputs)}";
//当方法名和参数都不变, 则表示有缓存 if (CachingBehaviorDictionary.ContainsKey(key))
{
return input.CreateMethodReturn(CachingBehaviorDictionary[key]);//直接返回 [短路器] 不再往下; 包括后面的Behavior也不会再执行了; 因为全部被直接短路了
}
else
{
//如果字典中没有, 则继续执行这里
IMethodReturn result = getNext().Invoke(input, getNext);
if (result.ReturnValue != null) //并将其加入到缓存列表中去; 当然缓存中放一个null没有任何意义, 所以这里判断一下
{
//不存在则, 加入缓存中
CachingBehaviorDictionary.Add(key, result.ReturnValue);
} return result;
} } public bool WillExecute
{
get { return true; }
}
}

l) UnityConfigAOP代码(调用):

 /// <summary>
/// 使用EntLib\PIAB Unity 实现动态代理
///
/// 1. 添加引用→右键→添加 NuGet包, 添加Unity的包引用
/// 2. 这里添加的 Unity是5.8.13的版本, 而Unity.Interception是5.5.0; 因为最新的(5.5.5)不支持 .net 4.0
/// 3. Unity是一个 Unity的容器; 而Unity.Interception当Unity做AOP时的一个扩展
/// </summary>
public class UnityConfigAOP
{
public static void Show()
{
User user = new User()
{
Name = "孙悟空",
Password = ""
}; {
//1. 初始化UnityContainer容器
IUnityContainer container = new UnityContainer();
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); //2. 开始读取配置文件
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "CfgFiles\\Unity.Config");
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
UnityConfigurationSection configSection = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName); //3. 使用配置文件中aopContainer节点下的所有配置信息来初始化container这个AOP容器
configSection.Configure(container, "aopContainer"); //10. 这个aopContainer就是配置文件中的 <container name="aopContainer"> 这里这个容器的名称 ; 注意如果配置文件中的名字和这里的名字不一样就会报出以下错误:
// The container named "aopContainer" is not defined in this configuration section. // 在这里创建对象, 创建的规则就来自于配置文件的 <register type="MyAOP.UnityWay.IUserProcessor,MyAOP" mapTo="MyAOP.UnityWay.UserProcessor,MyAOP"> 这一行; 如果是 IUserProcessor 类型, 就是使用UserProcessor 来创建实例
IUserProcessor processor = container.Resolve<IUserProcessor>();
processor.RegUser(user); //4. 注意, 当程序运行到这里的时候, 正常情况应该是去调用userProcessor的Reguser方法, 但是由于在配置文件中进行了配置, 所以它会去执行 LogBeforeBehavior 的 Invoke的方法(当aopContainer这容器中只有一个LogBeforeBehavior的时候, 如果多个, 则那个方法在前面则优先执行, 其它的上依次的调)
User userNew1 = processor.GetUser(user); //调用GetUser的时候, 也会执行配置文件中对应配置了的方法 //演示缓存Behavior
User userNew2 = processor.GetUser(user);
}
}
}

20181122_C#中AOP_使用Unity实现AOP的更多相关文章

  1. 运用Unity实现AOP拦截器

    运用Unity实现AOP拦截器[结合异常记录实例] 本篇文章将通过Unity实现Aop异常记录功能:有关Unity依赖注入可以看前两篇文章: 1:运用Unity实现依赖注入[结合简单三层实例] 2:运 ...

  2. 运用Unity实现AOP拦截器[结合异常记录实例]

      本篇文章将通过Unity实现Aop异常记录功能:有关Unity依赖注入可以看前两篇文章: 1:运用Unity实现依赖注入[结合简单三层实例] 2:运用Unity实现依赖注入[有参构造注入] 另早期 ...

  3. Ioc 之 Unity的AOP功能

    前面我们介绍了Unity的依赖注入功能,现在来介绍下Unity的AOP功能.AOP是面向切面编程,它能够使我们在不改变现有代码结构的情况下额外的为其添加一些功能. 我们还是使用配置文件来对类型进行注入 ...

  4. Xcode中如何集成Unity

    项目中需要集成unity,摸索了大半周,碰到了很多坑,终于搞定. 我的方法是,通过unity导出一个空的iOS项目,然后再新建一个Xcode项目,针对配置页面一一对应.直到配置完全一样,然后倒入相关资 ...

  5. 在.NET项目中使用PostSharp,实现AOP面向切面编程处理

    PostSharp是一种Aspect Oriented Programming 面向切面(或面向方面)的组件框架,适用在.NET开发中,本篇主要介绍Postsharp在.NET开发中的相关知识,以及一 ...

  6. JavaEE开发之Spring中的依赖注入与AOP

    上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...

  7. unity中调试模型时unity崩溃问题

    这个问题是在我调试3D模型资源时出现的,每当在Scene场景中调试模型时unity崩溃,出现Unity Bug Reporter页面,反复出现这个问题,很烧脑 对于这个问题我表示很无语,但是经过不断查 ...

  8. JavaEE开发之Spring中的依赖注入与AOP编程

    上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...

  9. [译]如何在ASP.NET Core中实现面向切面编程(AOP)

    原文地址:ASPECT ORIENTED PROGRAMMING USING PROXIES IN ASP.NET CORE 原文作者:ZANID HAYTAM 译文地址:如何在ASP.NET Cor ...

随机推荐

  1. python装饰器中functools.wraps的作用详解

    直接上代码看效果: # 定义一个最简单的装饰器 def user_login_data(f): def wrapper(*args, **kwargs): return f(*args, **kwar ...

  2. New Concept English three (22)

    34w 54 Some plays are so successful that they run for years on end. In many ways, this is unfortunat ...

  3. 《机器学习》第三章——LDA

    import numpy as np x=np.zeros((2,17)) y=np.zeros((1,17)) def dataload(filename): f=open(filename) ar ...

  4. visual studio 菜单栏显示异常 插件安装异常 扩展异常修复

    这几天在使用Visual studio 的扩展插件的时候,遇见了菜单栏显示异常,解决方案显示异常的问题,如下: 经过自己的一顿摸索,解决方法如下,比如我在安装gitee或github插件之后就出现了这 ...

  5. Objective C - 1 - 实现一个MessageBox.Show

    @interface K3ViewController : UIViewController<UIAlertViewDelegate> @end #import "K3ViewC ...

  6. pkcs#5和pkcs#7填充的区别

    最近做到了关于加密和解密的部分. 使用算法AES的时候,涉及到数据填充的部分,数据的填充有很多种方案,用的比较多的有pkcs#5,pkcs#7, 下面的都是从网上转来的.结论就是在AES 的使用中,p ...

  7. js检测三角形是否包含一个点

    pointInTriangle:function(x0, y0, x1, y1, x2, y2, x3, y3) { var divisor = (y2 - y3)*(x1 - x3) + (x3 - ...

  8. UDP示例

    android学习笔记18--------------UDP示例 分类: android2011-11-10 10:07 848人阅读 评论(0) 收藏 举报 androidbufferexcepti ...

  9. java 实现共享锁和排它锁

    一直对多线程有恐惧,在实现共享锁和排它锁之后,感觉好了很多. 共享锁    就是查询的时候,如果没有修改,可以支持多线程查询: 排它锁    就是修改的时候,锁定共享锁,停止查询,同时,锁定排它锁,只 ...

  10. BZOJ4709 Jsoi2011 柠檬【决策单调性+单调栈】

    Description Flute 很喜欢柠檬.它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬.贝壳一共有 N (1 ≤ N ≤ 100,000) 只,按顺序串在树枝上.为了方便,我们从 ...