使用动态基地址改装客户端

Posted

技术标签:

【中文标题】使用动态基地址改装客户端【英文标题】:Refit Client using a dynamic base address 【发布时间】:2020-02-24 23:11:13 【问题描述】:

我正在使用 Refit 在 asp.net core 2.2 中使用 Typed Client 调用 API,该 API 目前使用配置选项中的单个 BaseAddress 进行引导:

services.AddRefitClient<IMyApi>()
        .ConfigureHttpClient(c =>  c.BaseAddress = new Uri(myApiOptions.BaseAddress);)
        .ConfigurePrimaryHttpMessageHandler(() => NoSslValidationHandler)
        .AddPolicyHandler(pollyOptions);

在我们的配置 json 中:

"MyApiOptions": 
    "BaseAddress": "https://server1.domain.com",

在我们的 IMyApi 界面中:

public IMyAPi interface 
        [Get("/api/v1/question/")]
        Task<IEnumerable<QuestionResponse>> GetQuestionsAsync([AliasAs("document_type")]string projectId);

当前服务示例:

public class MyProject 
     private IMyApi _myApi;
     public MyProject (IMyApi myApi) 
        _myApi = myApi;
     

    public Response DoSomething(string projectId) 
        return _myApi.GetQuestionsAsync(projectId);
    

我现在需要在运行时根据数据使用不同的 BaseAddress。我的理解是 Refit 将 HttpClient 的单个实例添加到 DI 中,因此在运行时切换 BaseAddresses 不会直接在多线程应用程序中工作。现在注入 IMyApi 实例并调用接口方法 GetQuestionsAsync 非常简单。此时设置 BaseAddress 为时已晚。如果我有多个 BaseAddress,是否有一种简单的方法可以动态选择一个?

示例配置:

    "MyApiOptions": 
        "BaseAddresses": 
            "BaseAddress1": "https://server1.domain.com",
            "BaseAddress2": "https://server2.domain.com"
        

未来服务示例:

public class MyProject 
     private IMyApi _myApi;
     public MyProject (IMyApi myApi) 
        _myApi = myApi;
     

    public Response DoSomething(string projectId) 
        string baseUrl = SomeOtherService.GetBaseUrlByProjectId(projectId);

        return _myApi.UseBaseUrl(baseUrl).GetQuestionsAsync(projectId);
    

更新 根据接受的答案,我最终得到以下结果:

public class RefitHttpClientFactory<T> : IRefitHttpClientFactory<T>

    private readonly IHttpClientFactory _clientFactory;

    public RefitHttpClientFactory(IHttpClientFactory clientFactory)
    
        _clientFactory = clientFactory;
    

    public T CreateClient(string baseAddressKey)
    
        var client = _clientFactory.CreateClient(baseAddressKey);

        return RestService.For<T>(client);
    

【问题讨论】:

【参考方案1】:

注入 ClientFactory 而不是客户端:

public class ClientFactory

    public IMyApi CreateClient(string url) => RestService.For<IMyApi>(url);


public class MyProject 
     private ClientFactory _factory;
     public MyProject (ClientFactory factory) 
        _factory = factory;
     

    public Response DoSomething(string projectId) 
        string baseUrl = SomeOtherService.GetBaseUrlByProjectId(projectId);
        var client = _factory.CreateClient(baseUrl);

        return client.GetQuestionsAsync(projectId);
    

【讨论】:

谢谢。 2个问题。 1)这对启动引导程序有何影响,即我是否只需删除 .ConfigureHttpClient() 调用? 2)也许我应该在问题中说这个,但是会有很多像 DoSomething() 这样的函数调用 IMyApi 上的各种端点。有没有办法从 MyProject 重构 Client Creation 并巧妙地将其注入,否则我将在每个方法中重复 DoSomething() 中的前两行? 我不确定引导,这取决于您使用的 DI 方法。一种可能性是完全放弃引导并在您的 DI 容器中注册 ClientFactory 您可以将工厂的Create 方法更改为CreateForProject(string projectId) 并在该方法中查找URL。 我注意到的一件事是 RestService.For(url) 在每个请求上创建一个 New HttpClient。我的偏好是为每个 baseAddress 使用静态实例以减少内存/cpu/线程等。我注意到 IHttpClientFactory 可以添加命名实例,但不确定这将如何工作...... @sarin 您是否解决了为从 ClientFactory 获取的每个实例创建新 HttpClients 的问题?

以上是关于使用动态基地址改装客户端的主要内容,如果未能解决你的问题,请参考以下文章

搭建DHCP服务实现动态分配IP地址详解

VS2008下安装与配置DirectShow SDK 9.0 及 DirectShow AMCap改装的问题

DHCP

DHCP

java版gRPC实战之六:客户端动态获取服务端地址

谁能帮我改装一下,默认的时候把二级菜单隐藏,需要显示的时候点一下一级分类就可