AspectCore入门

安装依赖

Install-Package AspectCore.Extensions.DependencyInjection

定义特性类

使用抽象的 AbstractInterceptorAttribute 自定义特性类(该类实现了 IInterceptor 接口)。AspectCore默认实现了基于 Attribute 的拦截器配置,自定义的拦截器如下:

public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
{
    public async override Task Invoke(AspectContext context, AspectDelegate next)
    {
        try
        {
            Console.WriteLine("Before service call");
            await next(context);
        }
        catch (Exception)
        {
            Console.WriteLine("Service threw an exception!");
            throw;
        }
        finally
        {
            Console.WriteLine("After service call");
        }
    }
}

定义服务

自定义的特性类可以放在服务接口上

public interface ICustomService
{
    [CustomInterceptor]
    void Call();
}

public class CustomService : ICustomService
{
    public void Call()
    {
        Console.WriteLine("service calling...");
    }
}

控制器

public class HomeController : Controller
{
    private readonly ICustomService _service;
    public HomeController(ICustomService service)
    {
        _service = service;
    }

    public IActionResult Index()
    {
        _service.Call();
        return View();
    }
}

因为控制器层需要调用我们的服务,所以需要在程序启动时添加DI:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<ICustomService, CustomService>();
    services.ConfigureDynamicProxy();
    
    services.AddControllers();
}

Program.cs

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })
            // 略
            .UseServiceProviderFactory(new DynamicProxyServiceProviderFactory());

拦截器配置

全局拦截器

使用 ConfigureDynamicProxy(Action<IAspectConfiguration>) 的重载方法,其中 IAspectConfiguration 提供 Interceptors 注册全局拦截器。

//全局拦截器
services.ConfigureDynamicProxy(config =>
{
    config.Interceptors.AddTyped<CustomInterceptorAttribute>();
});

带参数的全局拦截器

CustomInterceptorAttribute 中添加带参数的构造器

    public class ParamsInterceptorAttribute : AbstractInterceptorAttribute
    {
        private string _name;
        public ParamsInterceptorAttribute(string name)
        {
            this._name = name;
        }

        public override async Task Invoke(AspectContext context, AspectDelegate next)
        {
            try
            {
                Console.WriteLine("Before service call");
                await next(context);
            }
            catch (Exception)
            {
                Console.WriteLine("Service threw an exception!");
                throw;
            }
            finally
            {
                Console.WriteLine("After service call");
            }
        }
    }

在Startup中注册

services.ConfigureDynamicProxy(config =>
{
    config.Interceptors.AddTyped<ParamsInterceptorAttribute>(args: new object[] { "custom" });
});

作为服务的全局拦截器

services.AddTransient<ParamsInterceptorAttribute>(provider => new ParamsInterceptorAttribute("custom"));
services.ConfigureDynamicProxy(config =>
{
    config.Interceptors.AddServiced<ParamsInterceptorAttribute>();
});

作用域特定Service或Method的全局拦截器

//作用于特定Service或Method的全局拦截器,本例为作用于带有 Service 后缀的类的全局拦截器
services.ConfigureDynamicProxy(config =>
{
    //根据 Method 做全局拦截(Controller中的 Method)
    config.Interceptors.AddTyped<CustomInterceptorAttribute>(method => method.Name.EndsWith("Params"));
    
    //根据 Service 做全局拦截(是用了通配符)
    //config.Interceptors.AddTyped<CustomInterceptorAttribute>(Predicates.ForService("*Service"));
});

NonAspectAttribute

在 AspectCore中提供了 NonAspectAttribute 来使得Service或Method不被代理

[NonAspect]
public interface ICustomService
{
    void Call();
}

同时支持全局忽略配置,亦支持通配符

services.ConfigureDynamicProxy(config =>
{
    //App1命名空间下的Service不会被代理
    config.NonAspectPredicates.AddNamespace("App1");

    //最后一级为App1的命名空间下的Service不会被代理
    config.NonAspectPredicates.AddNamespace("*.App1");

    //ICustomService接口不会被代理
    config.NonAspectPredicates.AddService("ICustomService");

    //后缀为Service的接口和类不会被代理
    config.NonAspectPredicates.AddService("*Service");

    //命名为Query的方法不会被代理
    config.NonAspectPredicates.AddMethod("Query");

    //后缀为Query的方法不会被代理
    config.NonAspectPredicates.AddMethod("*Query");
}); 

拦截器的依赖注入

在拦截器中支持属性注入,构造器注入和服务定位器模式。

属性注入,在拦截器中拥有public get and set权限的属性标记[AspectCore.DependencyInjection.FromServiceContextAttribute]特性,即可自动注入该属性,如:

public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
{
    //ps : 只有使用 config.Interceptors.AddTyped<CustomInterceptorAttribute>(); 时,属性注入才生效, 
    //     不能使用以下这种方式 services.AddSingleton<CustomInterceptorAttribute>(); + services.ConfigureDynamicProxy(config => { config.Interceptors.AddServiced<CustomInterceptorAttribute>(); });
    [FromServiceContext]
    public ILogger<CustomInterceptorAttribute> Logger { get; set; }


    public override Task Invoke(AspectContext context, AspectDelegate next)
    {
        Logger.LogInformation("call interceptor");
        return next(context);
    }
}

构造器注入需要使拦截器作为Service,除全局拦截器外,仍可使用ServiceInterceptor使拦截器从DI中激活:

public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
{
    private readonly ILogger<CustomInterceptor> ctorlogger;

    // ps : 当全局配置 config.Interceptors.AddTyped<CustomInterceptorAttribute>(); 时,构造器注入无法自动注入,需要手动处理
    //      只有使用 services.AddSingleton<CustomInterceptorAttribute>(); + services.ConfigureDynamicProxy(config => { config.Interceptors.AddServiced<CustomInterceptorAttribute>(); }); 才会自动注入
    public CustomInterceptor(ILogger<CustomInterceptor> ctorlogger)
    {
        this.ctorlogger = ctorlogger;
    }
}

服务定位器模式。拦截器上下文AspectContext可以获取当前Scoped的ServiceProvider

public class CustomInterceptorAttribute : AbstractInterceptorAttribute 
{
    public override Task Invoke(AspectContext context, AspectDelegate next)
    {
        var logger = context.ServiceProvider.GetService<ILogger<CustomInterceptorAttribute>>();
        logger.LogInformation("call interceptor");
        return next(context);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值