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

使用依赖注入(DI)在类内部重建损坏APIClient的最佳方案

实现方案说明

你的包装类方案合理性

你提出的IMyAPIClient包装类方案完全合理,符合依赖倒置原则,不会让业务类和DI容器产生强耦合,适合需要在多个依赖IMyAPIClient的类中复用重建、重试逻辑的场景。
同时还有更轻量的实现方案可选,你可以根据自己的业务场景选择:

方案1:注入工厂委托(最轻量,无需新增类)

你不需要在业务类中直接引用DI容器,只需要在构造函数中注入一个异步工厂委托,把客户端创建逻辑完全放到DI组合根处理即可,修改后的代码如下:

public class MyObject
{
    protected IMyAPIClient Client { get; set; }
    // 注入异步工厂委托,不关心客户端具体创建逻辑
    private readonly Func<Task<IMyAPIClient>> _clientFactory;
    private const int MAX_ATTEMPTS = 3;

    public MyObject(Func<Task<IMyAPIClient>> clientFactory)
    {
        _clientFactory = clientFactory;
        // 初始化首次客户端实例
        Client = _clientFactory().GetAwaiter().GetResult();
    }

    protected async Task<ReturnType> Run<ReturnType>(Func<Task<ReturnType>> action, int attempt = 1)
    {
        try
        {
            return await action();
        }
        catch(Exception exception)
        {
            // 直接通过工厂获取新实例,无DI容器依赖
            Client = await _clientFactory();
            if(attempt > MAX_ATTEMPTS)
            {
                throw new Exception($"Failed {attempt} times", exception);
            }
            // 注意原代码的attempt++是后置自增,会导致传入递归的还是原值引发死循环,这里改为attempt+1
            return await Run(action, attempt + 1);
        }
    }
}

DI容器注册示例(以ASP.NET Core内置DI为例),所有客户端创建逻辑都在组合根处理,业务代码完全不感知DI容器存在:

services.AddSingleton<MyObject>(sp => 
{
    return new MyObject(async () => 
    {
        // 这里可以从DI容器获取工厂创建新实例,也可以直接写创建逻辑
        var clientFactory = sp.GetRequiredService<IMyAPIClientFactory>();
        return await clientFactory.CreateNewAsync();
    });
});

方案2:自动恢复包装类(适合多场景复用)

如果有多个类依赖IMyAPIClient,你可以把重建、重试逻辑全部封装到包装类中,原有业务代码不需要做任何修改:

// 实现IMyAPIClient接口,作为可自动恢复的包装类
public class RecoverableMyAPIClient : IMyAPIClient
{
    private IMyAPIClient _innerClient;
    private readonly Func<Task<IMyAPIClient>> _clientFactory;
    private const int MAX_ATTEMPTS = 3;

    public RecoverableMyAPIClient(Func<Task<IMyAPIClient>> clientFactory)
    {
        _clientFactory = clientFactory;
        _innerClient = _clientFactory().GetAwaiter().GetResult();
    }

    // 实现IMyAPIClient的所有接口方法,统一封装重试逻辑
    public async Task<TResult> CallSomeApiAsync<TParam, TResult>(TParam param)
    {
        int attempt = 1;
        while(attempt <= MAX_ATTEMPTS)
        {
            try
            {
                return await _innerClient.CallSomeApiAsync<TParam, TResult>(param);
            }
            catch
            {
                _innerClient = await _clientFactory();
                attempt++;
                if(attempt > MAX_ATTEMPTS) throw;
            }
        }
        throw new InvalidOperationException("重试次数耗尽,API客户端恢复失败");
    }
}

DI注册时直接把包装类注册为IMyAPIClient的实现即可,原有依赖IMyAPIClient的业务类不需要修改一行代码:

// 注册可自动恢复的客户端实现
services.AddScoped<IMyAPIClient, RecoverableMyAPIClient>(sp => 
{
    return new RecoverableMyAPIClient(async () => 
    {
        // 真实客户端创建逻辑
        return new RealMyAPIClient(/* 配置参数 */);
    });
});
// 原有MyObject注册不需要修改
services.AddScoped<MyObject>();

内容的提问来源于stack exchange,提问作者Martien de Jong

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 22:36:03