【代码设计】C# 实现 AOP 面向切面编程

  • 【代码设计】C# 实现 AOP 面向切面编程已关闭评论
  • 156 次浏览
  • A+
所属分类:.NET技术
摘要

    简单记录一下对AOP的认识,正文为3个部分    一、AOP由来    二、用DispatchProxy动态代理实现AOP

    简单记录一下对AOP的认识,正文为3个部分

    一、AOP由来

    二、用DispatchProxy动态代理实现AOP

    三、通过特性标记,处理多种不同执行前、执行后的逻辑编排

 

一、AOP 由来

    IUserHelper userHelper = new CommonUserHelper();
// commonUser.Create中存在 方法执行前、方法执行后的业务逻辑 userHelper.Create("test0401_A"); public interface IUserHelper { void Create(string name); } public class CommonUserHelper : IUserHelper { private void before() { Console.WriteLine("CommonUser before"); } private void after() { Console.WriteLine("CommonUser after"); } public void Create(string name) { before(); Console.WriteLine($" Common User : {name} Created !"); after(); } }

CommonUserHelper 实现 IUserHelper 接口,假设希望在 Create方法执行前/后写入日志,那就存在这4种业务逻辑:

  ① 执行前写入日志,执行 Create

  ② 执行前写入日志,执行 Create,执行后写入日志

  ③ 执行 Create,执行后写入日志

  ④ 执行 Create

  单一个写日志的需求,就能有4种实现方式,极端情况下,是可以实现 4次 Create 方法;

  如果再加一个数据验证、IP验证、权限验证、异常处理、加入缓存..,那么实现的排列组合方式就更多了,

  无穷尽地加实现、替换类,这显然不是我们希望的。

AOP,Aspect Oriented Programing,是一种编程思维,是对这种缺陷的补充。

 

二、DispatchProxy (动态代理)实现AOP

using System.Reflection; namespace Cjm.AOP {     public class TransformProxy     {         public static T GetDynamicProxy<T>(T instance)           {             // DispatchProxy 是system.Reflection封装的类             // 用以创建实现接口T的代理类CustomProxy的实例             dynamic obj = DispatchProxy.Create<T, CustomProxy<T>>();             obj.Instance = instance;             return (T)obj;         }     }      // DispatchProxy 是抽象类,     // 实现该类的实例,实例方法执行是会跳转到 Invoke 方法中,     // 以此达到不破坏实际执行的具体逻辑,而又可以在另外的地方实现执行前、执行后     public class CustomProxy<T> : DispatchProxy     {         public T Instance { get; set; }         protected override object? Invoke(MethodInfo? targetMethod, object?[]? args)         {             BeforeProcess();             var relt = targetMethod?.Invoke(Instance, args);             AfterProcess();             return relt;         }          private void BeforeProcess()         {             Console.WriteLine($"This is BegoreProcess.");         }          private void AfterProcess()         {             Console.WriteLine($"This is AfterProcess.");         }     } }      // Main     IUserHelper userHelper3 = new CommonUserHelper();     userHelper3 = TransformProxy.GetDynamicProxy(userHelper3);     userHelper3.Create("test0401_B");

 

三、通过标记特性,处理多种不同的执行前/执行后方法

  此处借用Castle.Core的封装(可通过Nuget管理下载),

  通过实现 StandardInterceptor以重写 执行前/执行后 逻辑的封装方式,

  我们可以更加聚焦在如何处理多种 执行前/执行后 逻辑的编排上。

using Castle.DynamicProxy; {     ProxyGenerator proxy = new ProxyGenerator();     CustomInterceptor customInterceptor = new CustomInterceptor();     IUserHelper commonUserHelper = new CommonUserHelper();     var userHelperProxy = proxy.CreateInterfaceProxyWithTarget<IUserHelper>(commonUserHelper, customInterceptor);     userHelperProxy.Create("TEST0401_C"); }    

    public class CustomInterceptor : StandardInterceptor     {         protected override void PreProceed(IInvocation invocation)         {             var method = invocation.Method;             //if (method.IsDefined(typeof(LogBeforeAttribute), true))             //{             //    Console.WriteLine("LOG : CustomInterceptor.PreProceed");             //}              Action<IInvocation> action = (invocation) => base.PreProceed(invocation);             // 获取该方法的所有继承BaseAOPAttribute的特性             var attrs = method.GetCustomAttributes<BaseAOPAttribute>(true);
// 对于 attrs 的排列顺序,可以在特性的实现中增加 int order 属性,在标记特性时写入排序编号
foreach(var attr in attrs) { // 这里是俄罗斯套娃 // 相当于 attr3.AOPAction(invocation, attr2.AOPAction(invocation, attr1.AOPAction(invocation, base.PreProceed(invocation)))) action = attr.AOPAction(invocation, action); } action.Invoke(invocation); } protected override void PerformProceed(IInvocation invocation) { Console.WriteLine("CustomInterceptor.PerformProceed"); base.PerformProceed(invocation); } protected override void PostProceed(IInvocation invocation) { var method = invocation.Method; if (method.IsDefined(typeof(LogAfterAttribute), true)) { Console.WriteLine("LOG : CustomInterceptor.PostProceed"); } base.PreProceed(invocation); } }

    public class LogBeforeAttribute : Attribute {}      public class LogAfterAttribute : Attribute {}      public class CheckIPAttribute : BaseAOPAttribute     {         public override Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action)         {             return (invocation) => {                 Console.WriteLine("CheckIP ..");                 action.Invoke(invocation); 
}; } }
public abstract class BaseAOPAttribute : Attribute { public abstract Action<IInvocation> AOPAction(IInvocation invocation, Action<IInvocation> action); }

  通过给方法标记特性的方式,达到切面编程的目的(不影响原有实现,而增加实现执行前/执行后的逻辑)

    public interface IUserHelper     {         [LogBefore]         [LogAfter]         [CheckIP]         void Create(string name);          void CreateNoAttri();     }

 

============================================================

具体的AOP实现上需要考虑的问题多如牛毛,此处仅做简单的思路介绍。

以上主要参考自 B站 朝夕教育 2022 .Net Core AOP实现。