ASP.NET Core 3.0 使用AspectCore-Framework實現AOP

AspectCore是適用於Asp.Net Core 平臺的輕量級Aop(Aspect-oriented programming)解決方案,它更好的遵循Asp.Net Core的模塊化開發理念,使用AspectCore能夠更容易構建低耦合、易擴展的Web應用程序。git

在使用過程當中,因爲相關文檔、博客還未更新到.Net Core 3.0,本文操做參考了使用.Net Core 3.0的EasyCaching,並對其中公用的方法進行封裝簡化。github

安裝Aspectcore

此處配合微軟自家的DI實現,安裝Nuget包AspectCore.Extensions.DependencyInjection,其中包含AspectCore.Core和Microsoft.Extensions.DependencyInjection兩個依賴。web

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擴展IServiceCollectionshell

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中註冊服務c#

public void ConfigureServices(IServiceCollection services)
{   
    services.ConfigAspectCore();
}

3.在Program.cs中替換ServiceProviderFactoryasp.net

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

相關連接

相關文章
相關標籤/搜索