LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

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

freeflydom
2024年9月13日 9:24 本文热度 624

什么是 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<IMyService>(  

            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<ContainerBuilder>(autofacBuilder =>

                        {

                       

                            autofacBuilder.RegisterType<LoggingInterceptor>();

                                             

                            autofacBuilder.RegisterType<UserService>().As<IUserService>    ().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<UserService>().As<IUserService>().EnableInterfaceInterceptors() // 启用接口拦截器

使用 InterceptedBy() 方法

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

                            autofacBuilder.RegisterType<UserService>().As<IUserService>()    

                            .EnableInterfaceInterceptors() // 启用接口拦截器

                            .InterceptedBy(typeof(LoggingInterceptor)); //指定拦截器

实现事务管理

拦截器基类

    /// <summary>

    /// 拦截基类

    /// </summary>

    /// <typeparam name="T"></typeparam>

    public abstract class BaseInterceptor<T> : IInterceptor

    {

        protected readonly ILogger<T> _logger;

        public BaseInterceptor(ILogger<T> logger)

        {

            _logger = logger;

        }


        /// <summary>

        /// 拦截方法

        /// </summary>

        /// <param name="invocation"></param>

        public virtual void Intercept(IInvocation invocation)

        {

            try

            {

                Method = invocation.MethodInvocationTarget ?? invocation.Method;

                InterceptHandle(invocation);

            }

            catch (Exception ex)

            {

                _logger.LogError(ex, ex.Message);

                throw ex;

            }         

        }


        /// <summary>

        /// 拦截处理

        /// </summary>

        /// <param name="invocation"></param>

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

            );

        }

}

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

    /// <summary>

    /// 事务特性

    /// </summary>

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]

    public class TransactionalAttribute : Attribute

    {

        public TransactionalAttribute()

        {

            Timeout = 60;

        }


        /// <summary>

        /// 

        /// </summary>

        public int Timeout { get; set; }


        /// <summary>

        /// 事务隔离级别

        /// </summary>

        public IsolationLevel IsolationLevel { get; set; }


        /// <summary>

        /// 事务传播方式

        /// </summary>

        public Propagation Propagation { get; set; }

    }


    /// <summary>

    /// 事务传播方式

    /// </summary>

    public enum Propagation

    {

        /// <summary>

        /// 默认:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中。

        /// </summary>

        Required = 0,


        /// <summary>

        /// 使用当前事务,如果没有当前事务,就抛出异常

        /// </summary>

        Mandatory = 1,


        /// <summary>

        /// 以嵌套事务方式执行

        /// </summary>

        Nested = 2,

    }


事务拦截器:处理事务的

    /// <summary>

    /// 事务拦截器

    /// </summary>

    public class TransactionalInterceptor : BaseInterceptor<TransactionalInterceptor>

    {

        public TransactionalInterceptor(ILogger<TransactionalInterceptor> logger) : base(logger)

        {


        }


        public override void InterceptHandle(IInvocation invocation)

        {

            

            if (Method.GetCustomAttribute<TransactionalAttribute>(true) == null && Method.DeclaringType?.GetCustomAttribute<TransactionalAttribute>(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<ContainerBuilder>(autofacBuilder =>

                        {

                            autofacBuilder.RegisterType<TransactionalInterceptor>();                                      

                            autofacBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance().AsImplementedInterfaces()

                            .EnableInterfaceInterceptors()

                            .InterceptedBy(typeof(TransactionalInterceptor));

                        });


测试

实现用户自动填充

上下户用户

    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<ContainerBuilder>(autofacBuilder =>

                        {

                       

                            autofacBuilder.RegisterType<HttpContextUser>().As<IHttpContextUser>().SingleInstance().AsImplementedInterfaces();

                            autofacBuilder.RegisterType<UserAutoFillInterceptor>();

                       

                       

                            autofacBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance().AsImplementedInterfaces()

                            .EnableInterfaceInterceptors()

                            .InterceptedBy(typeof(UserAutoFillInterceptor));

                        });


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

    /// <summary>

    /// 用户自动填充拦截器

    /// </summary>

    public class UserAutoFillInterceptor : BaseInterceptor<UserAutoFillInterceptor>

    {

        private readonly IHttpContextUser _user;

        public UserAutoFillInterceptor(ILogger<UserAutoFillInterceptor> 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();

            }

        }

    }


测试



该文章在 2024/9/13 9:24:52 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2024 ClickSun All Rights Reserved