aspectcore是适用于asp.net core 平台的轻量级aop(aspect-oriented programming)解决方案,它更好的遵循asp.net core的模块化开发理念,使用aspectcore可以更容易构建低耦合、易扩展的web应用程序。
在使用过程中,由于相关文档、博客还未更新到.net core 3.0,本文操作参考了使用.net core 3.0的easycaching,并对其中公用的方法进行封装简化。
安装aspectcore
此处配合微软自家的di实现,安装nuget包aspectcore.extensions.dependencyinjection,其中包含aspectcore.core和microsoft.extensions.dependencyinjection两个依赖。
install-package aspectcore.extensions.dependencyinjection -version 1.3.0
拦截器
- 特性拦截器
新建一个特性拦截器testinterceptorattribute,继承abstractinterceptorattribute,并重写invoke方法,在方法中实现拦截相关业务。
public class testinterceptorattribute : abstractinterceptorattribute { public override task invoke(aspectcontext context, aspectdelegate next) { return context.invoke(next); } }
- 全局拦截器
新建一个全局拦截器testinterceptor,继承abstractinterceptor,并重写invoke方法,在方法中实现拦截相关业务。
public class testinterceptor : abstractinterceptor { public override task invoke(aspectcontext context, aspectdelegate next) { return context.invoke(next); } }
注册服务
以下注册方式仅适用于asp.net core 3.0(目前只到3.0),已知在2.2版本中,需要在configureservices方法中返回iserviceprovider,并且program.cs中也不再需要替换serviceproviderfactory。
1.创建aspectcoreectensions.cs扩展iservicecollection
public static class aspectcoreextensions { public static void configaspectcore(this iservicecollection services) { services.configuredynamicproxy(config => { //testinterceptor拦截器类 //拦截代理所有service结尾的类 config.interceptors.addtyped<testinterceptor>(predicates.forservice("*service")); }); services.buildaspectinjectorprovider(); } }
2.在startup.cs中注册服务
public void configureservices(iservicecollection services) { services.configaspectcore(); }
3.在program.cs中替换serviceproviderfactory
public static ihostbuilder createhostbuilder(string[] args) => host.createdefaultbuilder(args) .configurewebhostdefaults(webbuilder => { webbuilder.usestartup<startup>(); }).useserviceproviderfactory(new aspectcoreserviceproviderfactory());
被拦截方法编写
- 代理接口:在接口上标注attribute
public interface itestservice { [testinterceptor] void test(); }
- 代理类(方法):在方法上标注attribute,并且标注virtual
public class testservice { [testinterceptor] public virtual void test() { //业务代码 } }
拦截器业务编写
- 执行被拦截方法
private async task<object> runandgetreturn() { await context.invoke(next); return context.isasync() ? await context.unwrapasyncreturnvalue() : context.returnvalue; }
- 拦截器中的依赖注入
[fromcontainer] private redisclient redisclient { get; set; }
- 获取被拦截方法的attribute
private static readonly concurrentdictionary<methodinfo, object[]> methodattributes = new concurrentdictionary<methodinfo, object[]>(); public static t getattribute<t>(this aspectcontext context) where t : attribute { methodinfo method = context.servicemethod; var attributes = methodattributes.getoradd(method, method.getcustomattributes(true)); var attribute = attributes.firstordefault(x => typeof(t).isassignablefrom(x.gettype())); if (attribute is t) { return (t)attribute; } return null; }
- 获取被拦截方法返回值类型
public static type getreturntype(this aspectcontext context) { return context.isasync() ? context.servicemethod.returntype.getgenericarguments()first() : context.servicemethod.returntype; }
- 处理拦截器返回结果
private static readonly concurrentdictionary<type, methodinfo> typeoftaskresultmethod = new concurrentdictionary<type, methodinfo>(); public object resultfactory(this aspectcontext context,object result) { var returntype = context.getreturntype(); //异步方法返回task<t>类型结果 if (context.isasync()) { return typeoftaskresultmethod .getoradd(returntype, t => typeof(task) .getmethods() .first(p => p.name == "fromresult" && p.containsgenericparameters) .makegenericmethod(returntype)) .invoke(null, new object[] { result }); } else { return result; } }
相关链接
- github:本文代码
- github:aspectcore-framework
黄山市民网:https://www.huangshanshimin.com/