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