如何在C#中为Typed Client注册Castle DynamicProxy拦截器?
问题描述
已通过IHttpClientFactory为DemoMicroService创建基于Typed Client的HttpClient,希望使用Castle DynamicProxy定义的DemoMicroInterceptor拦截DemoMicroService中所有方法(Method1和Method2被应用服务或其他微服务调用时)的调用细节,请问如何在C#中为Typed Client注册该拦截器?
提供的代码文件如下:
DemoMicroService.cs
public class DemoMicroService: IDemoMicroService { private readonly HttpClient _httpClient; public DemoMicroService(HttpClient httpClient) { _httpClient = httpClient; } public async Task<XXXDto> Method1(int abc) { //Method1 Implementation } public async Task<XXXDto> Method2(int edf) { //Method2 Implementation } }
DemoMicroInterceptor.cs
public class DemoMicroInterceptor: IInterceptor { public DemoMicroInterceptor() { } public void Intercept(IInvocation invocation) { // Log the method name and input parameters var methodName = invocation.Method.Name; var inputParams = string.Join(",", invocation.Arguments.Select(a => a.ToString())); Debug.WriteLine($"Calling method {methodName} with parameters: {inputParams}"); // Invoke the original method invocation.Proceed(); // Log the return value var returnValue = invocation.ReturnValue; Debug.WriteLine($"Method {methodName} returned: {returnValue}"); } }
HttpApiHostModule.cs 中的Typed Client配置
private void ConfigureHttpClient(ServiceConfigurationContext context) { context.Services.AddHttpClient<DummyJsonService>(httpClient => { httpClient.BaseAddress = new Uri("https://dummyjson.com/"); }); }
注:当前配置无法让拦截器识别目标微服务,曾尝试相关方案但未成功。
解决方案
要实现Typed Client的Castle DynamicProxy拦截,需调整DI注册逻辑,同时修正拦截器对异步方法的处理:
步骤1:注册拦截器到DI容器
首先将DemoMicroInterceptor注册为可注入服务:
context.Services.AddTransient<DemoMicroInterceptor>();
步骤2:替换Typed Client的注册为代理实例
默认的AddHttpClient<DemoMicroService>会直接注册原始类型,需替换为通过Castle DynamicProxy创建的代理对象。修改ConfigureHttpClient方法:
private void ConfigureHttpClient(ServiceConfigurationContext context) { // 注册原始Typed Client的HttpClient配置 context.Services.AddHttpClient<DemoMicroService>(httpClient => { httpClient.BaseAddress = new Uri("你的微服务Base地址"); }); // 注册拦截器 context.Services.AddTransient<DemoMicroInterceptor>(); // 替换IDemoMicroService的注册为代理对象 context.Services.AddTransient<IDemoMicroService>(provider => { // 获取已注入HttpClient的原始DemoMicroService实例 var originalService = provider.GetRequiredService<DemoMicroService>(); // 获取拦截器实例 var interceptor = provider.GetRequiredService<DemoMicroInterceptor>(); // 创建代理生成器并生成代理 var proxyGenerator = new ProxyGenerator(); return proxyGenerator.CreateInterfaceProxyWithTarget<IDemoMicroService>(originalService, interceptor); }); }
步骤3:修正拦截器的异步方法处理
原拦截器直接读取invocation.ReturnValue会得到异步方法的Task对象,而非实际返回值,需修改Intercept方法适配异步场景:
public class DemoMicroInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { var methodName = invocation.Method.Name; var inputParams = string.Join(",", invocation.Arguments.Select(a => a?.ToString() ?? "null")); Debug.WriteLine($"Calling method {methodName} with parameters: {inputParams}"); // 执行原方法 invocation.Proceed(); // 区分异步/同步方法处理返回值 if (invocation.Method.ReturnType.IsGenericType && invocation.Method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>)) { // 处理带返回值的异步方法 var task = (Task)invocation.ReturnValue; task.ContinueWith(t => { if (t.IsCompletedSuccessfully) { var result = t.GetType().GetProperty("Result")?.GetValue(t); Debug.WriteLine($"Method {methodName} returned: {result?.ToString() ?? "null"}"); } else if (t.IsFaulted) { Debug.WriteLine($"Method {methodName} threw exception: {t.Exception?.InnerException?.Message}"); } }, TaskScheduler.Current); } else if (invocation.Method.ReturnType == typeof(Task)) { // 处理无返回值的异步方法 var task = (Task)invocation.ReturnValue; task.ContinueWith(t => { if (t.IsFaulted) { Debug.WriteLine($"Method {methodName} threw exception: {t.Exception?.InnerException?.Message}"); } else { Debug.WriteLine($"Method {methodName} completed successfully"); } }, TaskScheduler.Current); } else { // 处理同步方法 var returnValue = invocation.ReturnValue; Debug.WriteLine($"Method {methodName} returned: {returnValue?.ToString() ?? "null"}"); } } }
关键说明
- 保留
AddHttpClient<DemoMicroService>注册,确保DI自动管理HttpClient的注入和生命周期,代理仅包装原始实例。 - 使用
CreateInterfaceProxyWithTarget生成代理,既实现IDemoMicroService接口,又复用原始服务的依赖(如HttpClient)。 - 异步方法必须通过
ContinueWith处理返回值,否则日志仅会显示Task对象的默认ToString结果。
内容的提问来源于stack exchange,提问作者user22022766
相关产品推荐
相关产品推荐

