asp .net core 系列:基于 castle dynamicproxy autofac 实践 aop 以及实现事务、用户填充功能-kb88凯时官网登录

来自:
时间:2024-07-04
阅读:

什么是 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框架,但它经常被用作构建aopkb88凯时官网登录的解决方案的基础。

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 tasktest();
        void add(user user);
       void update(user user);
    }
    public class userservice : iuserservice
    {
        public void test()
        {
            console.writeline("test");
        }
        public async task 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 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 : 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));
                        });

测试

asp .net core 系列:基于 castle dynamicproxy   autofac 实践 aop 以及实现事务、用户填充功能

实现用户自动填充

上下户用户

    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();
            }
        }
    }

测试

asp .net core 系列:基于 castle dynamicproxy   autofac 实践 aop 以及实现事务、用户填充功能

返回顶部
顶部
网站地图