使用AspectCore動態代理


前言

最近越來越多的同學關注到AspectCore,並且提出不少中肯的建議,其中最多的提議是希望能夠看到更多的關於AspectCore使用方式的文章和Demo。那么在這篇文章里,我們就來聊聊AspectCore核心之一的動態代理。

動態代理

在.NET平台中,靜態織入和動態代理是實現AOP的兩種方式。其中靜態織入在編譯時通過在MSBiuld執行自定義的Build Task來攔截編譯過程,在生成的程序集里插入自己的IL。而動態代理則是在運行時通過Emit技術生成動態程序集和動態代理類型從而對目標方法進行攔截。不管那種方式,都需要對MSIL有足夠的理解,如果讀者想要學習MSIL相關的技術,我在這里推薦《NET探秘MSIL權威指南》一書。
AspectCore使用了動態代理作為AOP的實現,而不使用理論上性能更優的靜態織入實現,是由於個人覺得動態代理方式可以做到更好的IoC進行集成並且能夠在切面中獲取更多的運行時元數據信息,並且在經過不斷優化后,AspectCore動態代理的性能已經不落后靜態織入的實現方式。

如何使用

在之前的文章里,只是簡單的介紹了AspectCore,導致了很多同學不知道如何在項目里使用AspectCore(^~^,求輕拍~)。下面就來講一下如何在IoC環境和非IoC環境里使用AspectCore的AOP。
首先通過nuget獲取AspectCore:

Install-Package AspectCore.Core

AspectCore中動態代理api在AspectCore.DynamicProxy命名空間中,所以我們需要先引入命名空間

using AspectCore.DynamicProxy;

在非IoC環境中,只使用AOP的話,AspectCore提供了ProxyGeneratorBuilder作為代理生成器創建的入口

ProxyGeneratorBuilder proxyGeneratorBuilder = new ProxyGeneratorBuilder();
IProxyGenerator proxyGenerator = proxyGeneratorBuilder.Build();

IProxyGenerator提供了CreateClassProxy方法創建class代理和CreateInterfaceProxy方法創建interface代理,創建的代理類被定義在命名為AspectCore.DynamicProxy.Generator的動態程序集中,並且代理類使用AspectCore.DynamicGenerated命名空間。
我們先來定義一個簡單的攔截器,接着定義一個interface和它的簡單實現,並創建interface的代理:

class Program
{
    static void Main(string[] args)
    {
        ProxyGeneratorBuilder proxyGeneratorBuilder = new ProxyGeneratorBuilder();
        IProxyGenerator proxyGenerator = proxyGeneratorBuilder.Build();
        SampleInterface sampleInterface = proxyGenerator.CreateInterfaceProxy<SampleInterface,SampleClass>();
        Console.WriteLine(sampleInterface);
        sampleInterface.Foo();
        Console.ReadKey();
    }
}

public class SampleInterceptor : AbstractInterceptorAttribute
{
    public override Task Invoke(AspectContext context, AspectDelegate next)
    {
        Console.WriteLine("call interceptor");
        return context.Invoke(next);
    }
}

public class SampleClass : SampleInterface
{
    public virtual void Foo() { }
}

[SampleInterceptor]
public interface SampleInterface
{
    void Foo();
}

將會輸出:

AspectCore.DynamicGenerated.SampleInterface1
call interceptor

同時,IProxyGenerator提供了若干重載的擴展方法來創建已有類或接口實例的代理,可在ProxyGeneratorExtensions中找到並使用它們。

在IoC中使用AspectCore.DynamicProxy

AspectCore在設計之初就考慮AOP和IoC的集成使用,並提供AOP抽象接口以兼容不同IoC,目前已實現和AspectCore.DynamicProxy集成的IoC框架有:

  • AspectCore.Injector(AspectCore Framework的內置IoC)
  • Microsoft.Extensions.DependencyInjection(Asp.Net Core的內置DI框架)
  • Autofac

下面我們分別看一下在三個IoC中如何使用AspectCore.DynamicProxy。

AspectCore.Injector

AspectCore.Injector中內置了對AspectCore.DynamicProxy的支持,所以我們可以直接使用它:

IServiceContainer serviceContainer = new ServiceContainer();
serviceContainer.AddType<SampleInterface, SampleClass>();
IServiceResolver serviceResolver = serviceContainer.Build();
SampleInterface sampleInterface = serviceResolver.Resolve<SampleInterface>();
Console.WriteLine(sampleInterface);
sampleInterface.Foo();

輸出:

AspectCore.DynamicGenerated.SampleClass
call interceptor

Microsoft.Extensions.DependencyInjection

AspectCore提供AspectCore.Extensions.DependencyInjection包集成Microsoft.Extensions.DependencyInjection和AspectCore.DynamicProxy。
通過nuget獲取:

Install-Package AspectCore.Extensions.DependencyInjection

AspectCore提供了針對IServiceCollection的擴展方法AddDynamicProxy注冊動態代理的接口和相關攔截器配置,並需要使用BuildAspectCoreServiceProvider創建被DynamicProxy接管的ServiceProvider:

IServiceCollection services = new ServiceCollection();
services.AddTransient<SampleInterface, SampleClass>();

services.AddDynamicProxy();
IServiceProvider serviceProvider = services.BuildAspectCoreServiceProvider();

SampleInterface sampleInterface = serviceProvider.GetService<SampleInterface>();
Console.WriteLine(sampleInterface);
sampleInterface.Foo();

輸出:

AspectCore.DynamicGenerated.SampleClass
call interceptor

Autofac

AspectCore提供AspectCore.Extensions.Autofac包集成Autofac和AspectCore.DynamicProxy。
通過nuget獲取:

Install-Package AspectCore.Extensions.Autofac

AspectCore提供了針對ContainerBuilder的擴展方法RegisterDynamicProxy注冊動態代理的接口和相關攔截器配置

ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<SampleClass>().As<SampleInterface>();

builder.RegisterDynamicProxy();

var container = builder.Build();
SampleInterface sampleInterface = container.Resolve<SampleInterface>();
Console.WriteLine(sampleInterface);
sampleInterface.Foo();

輸出:

AspectCore.DynamicGenerated.SampleClass
call interceptor

有問題反饋

如果您有任何問題,請提交 Issue 給我們。
Github : https://github.com/dotnetcore/AspectCore-Framework
AspectCore QQ群: 306531723


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM