• Asp .Net Core 系列:基于 Castle DynamicProxy + Autofac 实践 AOP 以及实现事务、用户填充功能


    什么是 AOP ?

    AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在通过将横切关注点(cross-cutting concerns)从主要业务逻辑中分离出来,以提高代码的模块化性、可维护性和复用性。

    在传统的面向对象编程中,我们通常通过类和对象来组织和实现功能。然而,某些功能,如日志记录、事务管理、安全性检查等,可能会跨越多个对象和模块,这种跨越称为横切关注点。AOP 的核心思想是将这些横切关注点从业务逻辑中分离出来,通过特定的机制将它们应用到代码中,而不是通过直接修改业务逻辑来实现。

    .Net Core 中 有哪些 AOP 框架?

    PostSharp(收费)

    PostSharp是一个功能强大的AOP框架,它通过编译器插件的形式集成到Visual Studio中。PostSharp支持编译时AOP(通过C#特性应用切面),并提供了丰富的切面类型,包括方法拦截、属性访问拦截、异常处理等。它还提供了商业支持和丰富的文档。

    Castle DynamicProxy

    Castle DynamicProxy是Castle项目的一部分,它允许开发者在运行时动态创建代理类,这些代理类可以拦截对目标对象的调用,并在调用前后执行自定义逻辑。虽然它本身不是一个完整的AOP框架,但它经常被用作构建AOP解决方案的基础。

    AspectCore Framework

    AspectCore 是一个开源的 AOP 框架,专为 .NET Core 设计。它提供了基于动态代理的运行时切面和方法拦截机制,支持常见的切面编程需求,如日志、缓存、事务等。

    基于 Castle DynamicProxy 实现 AOP

    1. 安装Castle.Core NuGet包

    Install-Package Castle.Core
    

    2. 定义接口和类

    假设你有一个接口和一个实现了该接口的类,你想要拦截这个类的方法调用。

    public interface IMyService  
    {  
        void PerformAction();  
    }   
    public class MyService : IMyService  
    {  
        public void PerformAction()  
        {  
            Console.WriteLine("Action performed.");  
        }  
    }
    

    3. 创建拦截器

    接下来,你需要创建一个拦截器类,该类将实现IInterceptor接口。在这个接口的实现中,你可以定义在调用目标方法之前和之后要执行的逻辑。

    using Castle.DynamicProxy;  
      
    public class MyInterceptor : IInterceptor  
    {  
        public void Intercept(IInvocation invocation)  
        {  
            // 在调用目标方法之前执行的逻辑  
            Console.WriteLine("Before method: " + invocation.Method.Name);  
      
            // 调用目标方法  
            invocation.Proceed();  
      
            // 在调用目标方法之后执行的逻辑  
            Console.WriteLine("After method: " + invocation.Method.Name);  
        }  
    }
    

    4. 创建代理并调用方法

    最后,你需要使用ProxyGenerator类来创建MyService的代理实例,并指定拦截器。然后,你可以像使用普通对象一样调用代理的方法,但拦截器中的逻辑会在调用发生时执行。

    using Castle.DynamicProxy;  
      
    public class Program  
    {  
        public static void Main(string[] args)  
        {  
            var generator = new ProxyGenerator();  
            var interceptor = new MyInterceptor();  
      
            // 创建MyService的代理实例,并指定拦截器  
            var proxy = generator.CreateInterfaceProxyWithTarget(  
                new MyService(), interceptor);  
      
            // 调用代理的方法,拦截器中的逻辑将被执行  
            proxy.PerformAction();  
        }  
    }
    

    注意,上面的示例使用了接口代理(CreateInterfaceProxyWithTarget),这意味着你的目标类必须实现一个或多个接口。如果你想要代理一个类而不是接口,你可以使用CreateClassProxyWithTarget方法(但这通常用于需要代理非虚方法或字段的场景,且要求目标类是可继承的)。

    IOC中使用 Castle DynamicProxy

    由于IOC容器(如Microsoft的IServiceCollectionIServiceProvider)通常不直接支持AOP,所以用 Autofac
    1. 安装必要的 NuGet 包

    首先,确保你的项目中安装了以下 NuGet 包:

    Install-Package Autofac
    Install-Package Autofac.Extensions.DependencyInjection
    Install-Package Autofac.Extras.DynamicProxy
    Install-Package Castle.Core
    

    2. 创建服务接口和实现类

        public class User
        {
            public long Id { get; set; }
    
            public string Name { get; set; }
    
            public long CreateUserId { get; set; }
    
            public string CreateUserName { get; set; }
    
            public DateTime CreateTime { get; set; }
    
            public long UpdateUserId { get; set; }
    
            public string UpdateUserName { get; set; }
    
            public DateTime UpdateTime { get; set; }
        }    
    
        public interface IUserService
        {
            void Test();
    
            Task<int> TaskTest();
    
            void Add(User user);
    
           void Update(User user);
        }
    
    
        public class UserService : IUserService
        {
            public void Test()
            {
                Console.WriteLine("Test");
            }
    
            public async Task<int> TaskTest()
            {
                await Console.Out.WriteLineAsync("TaskTest");
                return 1;
            }
    
            public void Add(User user)
            {
                Console.WriteLine(user.CreateUserId);
                Console.WriteLine(user.CreateUserName);
            }
    
            public void Update(User user)
            {
                Console.WriteLine(user.UpdateUserId);
                Console.WriteLine(user.UpdateUserName);
            }
        }
    
        [ApiController]
        [Route("[controller]")]
        public class UserController : ControllerBase
        {
            readonly IUserService _userService;
    
            public UserController(IUserService userService)
            {
                _userService = userService;
            }        
    
            [HttpGet]
            [Route("/taskTest")]
            public async Task<string> TaskTest()
            {
                await _userService.TaskTest();
                return "ok";
            }
    
            [HttpGet]
            [Route("/test")]
            public string Test()
            {
                _userService.Test();
                return "ok";
            }
    
            [HttpGet]
            [Route("/add")]
            public string Add()
            {
                _userService.Add(new Model.User { Name = "张三" });
                return "ok";
            }
    
    
            [HttpGet]
            [Route("/update")]
            public string Update()
            {
                _userService.Update(new Model.User { Name = "张三" });
                return "ok";
            }
        }
    

    3. 创建拦截器类

    创建一个实现 IInterceptor 接口的拦截器类 LoggingInterceptor,用于拦截方法调用并添加日志记录:

    public class LoggingInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine($"Before executing: {invocation.Method.Name}");
    
            invocation.Proceed(); // 调用原始方法
    
            Console.WriteLine($"After executing: {invocation.Method.Name}");
        }
    }
    

    4. 配置 Autofac 容器

    builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //使用Autofac
                            .ConfigureContainer(autofacBuilder =>
                            {
                           
                                autofacBuilder.RegisterType();
                                                 
                                autofacBuilder.RegisterType().As    ().SingleInstance().AsImplementedInterfaces()    
                                .EnableInterfaceInterceptors() // 启用接口拦截器
                                .InterceptedBy(typeof(LoggingInterceptor)); //指定拦截器
                            });
    

    与Autofac集成时,配置拦截器主要有两种方式

    使用 InterceptAttribute 特性

    这种方式通过在接口或类上添加[Intercept(typeof(YourInterceptor))]特性来指定拦截器。然后,在Autofac注册时,启用接口或类的拦截器。(通常不推荐在类上直接添加,因为这会使类与Autofac紧密耦合)

     [Intercept(typeof(UserAutoFillInterceptor))]
     public class UserService : IUserService
    {  
         public void Test()
         {
            Console.WriteLine("Test");
         } 
    }
    
    autofacBuilder.RegisterType().As().EnableInterfaceInterceptors() // 启用接口拦截器
    

    使用 InterceptedBy() 方法

    这种方式不依赖于[Intercept]特性,而是在注册服务时直接使用InterceptedBy()方法来指定拦截器。

                                autofacBuilder.RegisterType().As()    
                                .EnableInterfaceInterceptors() // 启用接口拦截器
                                .InterceptedBy(typeof(LoggingInterceptor)); //指定拦截器
    

    实现事务管理

    拦截器基类

        /// 
        /// 拦截基类
        /// 
        /// 
        public abstract class BaseInterceptor<T> : IInterceptor
        {
            protected readonly ILogger _logger;
            public BaseInterceptor(ILogger logger)
            {
                _logger = logger;
            }
    
            /// 
            /// 拦截方法
            /// 
            /// 
            public virtual void Intercept(IInvocation invocation)
            {
                try
                {
                    Method = invocation.MethodInvocationTarget ?? invocation.Method;
                    InterceptHandle(invocation);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, ex.Message);
                    throw ex;
                }         
            }
    
            /// 
            /// 拦截处理
            /// 
            /// 
            public abstract void InterceptHandle(IInvocation invocation);
    
            protected MethodInfo Method{ get; set; }
    
            public static bool IsAsyncMethod(MethodInfo method)
            {
                return (method.ReturnType == typeof(Task) ||
                    (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
                );
            }
    }
    

    事务特性:用来判断是否需要事务管理的

        /// 
        /// 事务特性
        /// 
        [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
        public class TransactionalAttribute : Attribute
        {
            public TransactionalAttribute()
            {
                Timeout = 60;
            }
    
            /// 
            /// 
            /// 
            public int Timeout { get; set; }
    
            /// 
            /// 事务隔离级别
            /// 
            public IsolationLevel IsolationLevel { get; set; }
    
            /// 
            /// 事务传播方式
            /// 
            public Propagation Propagation { get; set; }
        }
    
        /// 
        /// 事务传播方式
        /// 
        public enum Propagation
        {
            /// 
            /// 默认:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中。
            /// 
            Required = 0,
    
            /// 
            /// 使用当前事务,如果没有当前事务,就抛出异常
            /// 
            Mandatory = 1,
    
            /// 
            /// 以嵌套事务方式执行
            /// 
            Nested = 2,
        }
    

    事务拦截器:处理事务的

        /// 
        /// 事务拦截器
        /// 
        public class TransactionalInterceptor : BaseInterceptor
        {
            public TransactionalInterceptor(ILogger logger) : base(logger)
            {
    
            }
    
            public override void InterceptHandle(IInvocation invocation)
            {
                
                if (Method.GetCustomAttribute(true) == null && Method.DeclaringType?.GetCustomAttribute(true) == null)
                {
                    invocation.Proceed();
                }
                else
                {
                    try
                    {
                        Console.WriteLine("开启事务");
    
                        //执行方法
                        invocation.Proceed();
    
                        // 异步获取异常,先执行
                        if (IsAsyncMethod(invocation.Method))
                        {
                            var result = invocation.ReturnValue;
                            if (result is Task)
                            {
                                Task.WaitAll(result as Task);
                            }
                        }
    
                        Console.WriteLine("提交事务");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("回滚事务");
                        _logger.LogError(ex, ex.Message);
                        throw ex;
                    }
                }
            }
        }
    

    接口上加入事务特性

        //[Transactional]
        public class UserService : IUserService
        {
    
            [Transactional]
            public void Test()
            {
                Console.WriteLine("Test");
            }
        }
    

    注入IOC

    builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                            .ConfigureContainer(autofacBuilder =>
                            {
                                autofacBuilder.RegisterType();                                      
                                autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces()
                                .EnableInterfaceInterceptors()
                                .InterceptedBy(typeof(TransactionalInterceptor));
                            });
    

    测试

    image

    实现用户自动填充

    上下户用户

        public interface IHttpContextUser
        {
             long UserId { get; }
    
             string UserName { get;}
        }
    
    
        public class HttpContextUser : IHttpContextUser
        {
            private readonly IHttpContextAccessor _accessor;
            public HttpContextUser(IHttpContextAccessor accessor)
            {
                _accessor = accessor;
            }
            public long UserId
            {
                get
                {
                    return 1; //这里暂时是写死的
                    if (int.TryParse(_accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Sid), out var userId))
                    {
                        return userId;
                    }
                    return default;
                }
            }
    
            public string UserName
            {
                get
                {
                    return "admin"; //这里暂时是写死的
                    return _accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name) ?? "";
                }
            }
        }
    
    
    

    注入IOC

               builder.Services.AddHttpContextAccessor();
               builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
                            .ConfigureContainer(autofacBuilder =>
                            {
                           
                                autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces();
                                autofacBuilder.RegisterType();
                           
                           
                                autofacBuilder.RegisterType().As().SingleInstance().AsImplementedInterfaces()
                                .EnableInterfaceInterceptors()
                                .InterceptedBy(typeof(UserAutoFillInterceptor));
                            });
    

    用户自动拦截器:处理用户填充的

        /// 
        /// 用户自动填充拦截器
        /// 
        public class UserAutoFillInterceptor : BaseInterceptor
        {
            private readonly IHttpContextUser _user;
            public UserAutoFillInterceptor(ILogger logger,IHttpContextUser user) : base(logger)
            {
                _user = user;
            }
    
            public override void InterceptHandle(IInvocation invocation)
            {
                //对当前方法的特性验证
                if (Method.Name?.ToLower() == "add" || Method.Name?.ToLower() == "update")
                {
                    if (invocation.Arguments.Length == 1 && invocation.Arguments[0].GetType().IsClass)
                    {
                        dynamic argModel = invocation.Arguments[0];
                        var getType = argModel.GetType();
                        if (Method.Name?.ToLower() == "add")
                        {
                            if (getType.GetProperty("CreateUserId") != null)
                            {
                                argModel.CreateUserId = _user.UserId;
                            }
                            if (getType.GetProperty("CreateUserName") != null)
                            {
                                argModel.CreateUserName = _user.UserName;
                            }
                            if (getType.GetProperty("CreateTime") != null)
                            {
                                argModel.CreateTime = DateTime.Now;
                            }
                         
                        }
                        if (getType.GetProperty("UpdateUserId") != null)
                        {
                            argModel.UpdateUserId = _user.UserId;
                        }
                        if (getType.GetProperty("UpdateUserName") != null)
                        {
                            argModel.UpdateUserName = _user.UserName;
                        }
                        if (getType.GetProperty("UpdateTime") != null)
                        {
                            argModel.UpdateTime = DateTime.Now;
                        }
                       
                        }
                    invocation.Proceed();
                }
                else
                {
                    invocation.Proceed();
                }
            }
        }
    

    测试

    image


    __EOF__

  • 本文作者: 书山有路勤为径,学海无涯苦作舟
  • 本文链接: https://www.cnblogs.com/vic-tory/p/18284779
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    Cpp知识点系列-宏定义
    Serlvet的三种创建方式
    前端面试的话术集锦第 7 篇:高频考点(浏览器渲染原理 & 安全防范)
    react hooks antd 父组件取子组件form表单的值
    自动代码Copilot背后的模型
    easyexecl导出100万行execl报字体错误的解决办法
    探究SpringWeb对于请求的处理过程
    vant 的 Cascader 级联选择 组建css样式错乱问题修复
    电脑怎么设置开机密码?简单几步给你的电脑“上锁”
    自然语言处理学习笔记(十)———— 停用词过滤
  • 原文地址:https://www.cnblogs.com/vic-tory/p/18284779