ASP.NET Core中IAsyncInterceptor未触发调用的问题排查
Castle.Core.AsyncInterceptor拦截器未触发问题排查与修复
问题背景
在ASP.NET Core 8 Web API项目中使用Castle.Core.AsyncInterceptor时,TerminalService的方法能正常调用,但拦截器始终未触发。以下是问题代码及修复方案:
核心错误原因
- 拦截器类型不兼容:Castle的代理生成方法
CreateInterfaceProxyWithTarget仅接受IInterceptor类型实例,而IAsyncInterceptor是独立的异步拦截接口,需通过AsyncInterceptorAdapter转换适配。 - 服务注册与获取不匹配:原代码注册的是
IAsyncInterceptor,但代理创建时尝试获取IInterceptor实例,导致无法拿到拦截器。 - Logger未正确初始化:原拦截器内Logger在方法内赋值,存在空引用风险,不符合依赖注入规范。
修复步骤及代码修改
1. 修改服务注册逻辑
调整拦截器注册方式,将IAsyncInterceptor包装为IInterceptor:
builder.Services.AddSingleton(new ProxyGenerator()); // 将AsyncInterceptor转换为IInterceptor类型注册 builder.Services.AddScoped<IInterceptor>(sp => new AsyncInterceptorAdapter(sp.GetRequiredService<LoggingInterceptor>())); builder.Services.AddProxiedScoped<ITerminalService, TerminalService>();
2. 修正AddProxiedScoped方法
确保代理创建时能正确获取并转换异步拦截器:
public static void AddProxiedScoped<TInterface, TImplementation>(this IServiceCollection services) where TInterface : class where TImplementation : class, TInterface { services.AddScoped<TImplementation>(); services.AddScoped(typeof(TInterface), serviceProvider => { var proxyGenerator = serviceProvider.GetRequiredService<ProxyGenerator>(); var actual = serviceProvider.GetRequiredService<TImplementation>(); // 获取异步拦截器并转换为IInterceptor var asyncInterceptor = serviceProvider.GetRequiredService<IAsyncInterceptor>(); var interceptors = new IInterceptor[] { new AsyncInterceptorAdapter(asyncInterceptor) }; return proxyGenerator.CreateInterfaceProxyWithTarget(typeof(TInterface), actual, interceptors); }); }
3. 完善LoggingInterceptor实现
通过构造函数注入Logger,确保日志功能正常:
public class LoggingInterceptor : IAsyncInterceptor { private readonly ILogger<LoggingInterceptor> _logger; // 构造函数注入ILogger public LoggingInterceptor(ILogger<LoggingInterceptor> logger) { _logger = logger; } public void InterceptSynchronous(IInvocation invocation) { _logger.Information("执行同步方法: {MethodName}", invocation.Method.Name); invocation.Proceed(); _logger.Information("同步方法完成: {MethodName}, 返回值: {ReturnValue}", invocation.Method.Name, invocation.ReturnValue); } public void InterceptAsynchronous(IInvocation invocation) { _logger.Information("执行异步方法: {MethodName}", invocation.Method.Name); invocation.ReturnValue = InternalInterceptAsynchronous(invocation); } public void InterceptAsynchronous<TResult>(IInvocation invocation) { _logger.Information("执行异步方法(带返回值): {MethodName}", invocation.Method.Name); invocation.ReturnValue = InternalInterceptAsynchronous<TResult>(invocation); } private async Task InternalInterceptAsynchronous(IInvocation invocation) { invocation.Proceed(); var task = (Task)invocation.ReturnValue; await task; _logger.Information("异步方法完成: {MethodName}", invocation.Method.Name); } private async Task<TResult> InternalInterceptAsynchronous<TResult>(IInvocation invocation) { invocation.Proceed(); var task = (Task<TResult>)invocation.ReturnValue; TResult result = await task; _logger.Information("异步方法(带返回值)完成: {MethodName}, 返回值: {Result}", invocation.Method.Name, result); return result; } }
验证
修改完成后,调用ITerminalService.SomeMethodAsync()时,拦截器的对应方法会被触发,日志中会输出方法执行的前后信息,确认拦截器生效。
内容的提问来源于stack exchange,提问作者Gringo
相关产品推荐
相关产品推荐

