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();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
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);
}
}
笨一点没关系,只要自己不放弃自己
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器