You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 16:20:42