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

yizhihongxing

    简单记录一下对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实现。

 

原文链接:https://www.cnblogs.com/carmen-019/p/17280096.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:【代码设计】C# 实现 AOP 面向切面编程 - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • Solaris 10 OS 快速安裝配置 Apache + Mysql + php

    Solaris 10 OS 快速安装配置 Apache + Mysql + PHP攻略 简介 本文介绍如何在 Solaris 10 操作系统上快速地安装配置 Apache、MySQL 和 PHP 环境。 步骤 1. 安装软件包管理器 # pkgadd -d http://get.opencsw.org/now 2. 安装 Apache # pkgutil -…

    C# 2023年5月31日
    00
  • 使用JavaScript和C#中获得referer

    获取referer主要用于获取用户从哪个页面跳转而来,在前端和后端均有相应方法。在JavaScript中可以使用document.referrer进行访问,在C#中可以使用Request.Headers[“Referer”]进行访问。下面是详细的攻略。 在JavaScript中获取referer 在前端中获取referer的方法比较简单,可以使用docume…

    C# 2023年6月6日
    00
  • c#与WMI使用技巧集第1/2页

    c#与WMI使用技巧集第1/2页是一篇介绍C#与WMI使用技巧的文章,主要包括WMI的基础知识、C#中如何使用WMI等方面的内容。以下是该文章完整攻略的详细讲解: WMI基础知识 WMI(Windows Management Instrumentation)是一种用于管理Windows操作系统的工具,可以用于获取系统信息、监控、配置等。在C#中使用WMI可以…

    C# 2023年6月6日
    00
  • C#如何在海量数据下的高效读取写入MySQL

    C#如何在海量数据下的高效读取写入MySQL攻略 1. 前置条件 已安装MySQL 已安装MySql.Data NuGet包 已创建数据库和数据表 2. 高效读取MySQL数据 要从MySQL数据库中读取大量数据,最好使用DataReader。它可以以只读方式快速读取大量数据,并且不会占用太多内存。下面是一个示例: try { using (MySqlCon…

    C# 2023年6月2日
    00
  • C# 10个常用特性汇总

    C# 10个常用特性汇总 在本文中,我们将介绍 C# 中的10个常用特性及其用例,包括: 可空引用类型(Nullable reference types) 模式匹配(Pattern matching) 捕获块(Catch block) 局部函数(Local functions) 海象运算符(Null coalescing assignment operato…

    C# 2023年6月7日
    00
  • C#学习教程之Socket的简单使用

    C#学习教程之Socket的简单使用 什么是Socket? Socket(套接字)是支持TCP/IP协议的网络通信方式,它是一种用于网络通信的编程接口或应用程序编程接口(API),使得两个进程之间可以通过网络进行数据交互。在 C# 中,可以使用 System.Net.Sockets 命名空间中的类来实现 Socket 的编程。 如何实现 Socket 编程?…

    C# 2023年6月6日
    00
  • ASP.NET Core 依赖注入生命周期示例详解

    ASP.NET Core 依赖注入生命周期示例详解攻略 在本攻略中,我们将深入讲解ASP.NET Core依赖注入生命周期,并提供两个示例说明。 什么是ASP.NET Core依赖注入生命周期? ASP.NET Core依赖注入生命周期是指在ASP.NET Core应用程序中注册和解析服务时,服务的生命周期如何管理。ASP.NET Core提供了三种生命周期…

    C# 2023年5月17日
    00
  • 采用easyui tree编写简单角色权限代码的方法

    下面我将为您详细讲解 “采用easyui tree编写简单角色权限代码的方法”的完整攻略,过程中将包含两条示例说明。 一、使用EasyUI Tree组件 1.1 引入EasyUI和jQuery 在使用EasyUI Tree组件前,需要先引入官方提供的EasyUI库和jQuery库。具体方法可以参考以下代码块: <!– 引入JQuery –> …

    C# 2023年6月1日
    00
合作推广
合作推广
分享本页
返回顶部