类型化 HttpClient 与 IHttpClientFactory

Iva*_*kin 20 c# async-await dotnet-httpclient asp.net-core httpclientfactory

以下两种设置 HttpClient 的场景有什么区别吗?

我应该选择其中一种而不是另一种吗?

键入的客户端:

public class CatalogService 
{
    private readonly HttpClient _httpClient;
    
    public CatalogService(HttpClient httpClient) {
        _httpClient = httpClient;
    }
    
    public async Task<string> Get() {
        var response = await _httpClient.GetAsync();
        ....
    }
    
    public async Task Post() {
        var response = await _httpClient.PostAsync();
        ...
    }
}
// Startup.cs
//Add http client services at ConfigureServices(IServiceCollection services)
services.AddHttpClient<ICatalogService, CatalogService>();
Run Code Online (Sandbox Code Playgroud)

IHttpClientFactory:

public class CatalogService 
{
    private readonly IHttpClientFactory _factory;
    
    public CatalogService(IHttpClientFactory factory) {
        _factory = factory;
    }
    
    public async Task<string> Get() {
        var response = await _factory.CreateClient().GetAsync();
        ....
    }
    
    public async Task Post() {
        var response = await _factory.CreateClient().PostAsync();
        ...
    }
}
// Startup.cs
//Add http client services at ConfigureServices(IServiceCollection services)
services.AddHttpClient();
```
Run Code Online (Sandbox Code Playgroud)

Pet*_*ala 16

版本控制:

  • 于 22 年 10 月 7 日更新,添加命名和类型客户端

我认为当你从消费的角度来看它们时,最大的区别就会显现出来。

类型化客户端

您将收到一个HttpClient实例,该实例可能已使用一些针对暂时性故障的弹性策略和一些默认值进行了装饰。BaseUrl您甚至可能会收到已经设置好的客户端。

因此,如果您需要将 REST API 客户端隐藏在强类型服务层后面,则此方法特别有用。

指定客户

当您需要来自特定客户端的多个实例或需要多个不同的客户端时,此技术可以发挥作用。如果您使用不同的名称注册了多个不同的客户端,那么您可以通过单个 API 轻松检索它们。

因此,如果您需要调用不同的下游系统并且需要聚合它们的结果,这种方法可能会很有用。

命名并输入客户端

还有第三种选择,它是上述两种选择的组合。您可以获得类型化客户端的强类型 API 以及命名客户端的独特命名功能。

当您想要针对不同的域(例如有一个主站点和一个辅助站点)使用相同类型的客户端 API 时,这尤其有用。或者您想要稍微不同的 Polly 策略(不同的下游系统可能需要不同的超时设置)...

在这里我详细介绍了如何创建和使用不同的客户端。

好文章值得阅读


Han*_*hao 5

IMO,我会通过HttpClient。原因是,

  1. KISS 原则-CatalogService真正需要的是HttpClient. 该服务并不关心如何获得客户。
  2. 单一职责原则 (SRP) - 假设明天您必须保留两个实例来CatalogService将请求发送到两个不同的端点,
    • 您可以传入 aIHttpClientFactory并在内部实现路由CatalogService,但这会破坏 SRP。
    • 或者,您可以创建一个CatalogServiceFactory. 该工厂被IHttpClientFactory传入并在内部实现路由。这也称为关注点分离


Tom*_*das -1

拥有抽象(即IHttpClient)要好得多,并且更受到社区的赞扬。它允许您分配HttpClient以及自定义编写而IHttpClient无需更改CatalogService

在创建大型系统时,这是非常关键的一点,因为对具体实现的依赖会减少,维护成本也会减少。

此外,使用抽象可以显示实际用途,并减少可能的干扰。一个例子:

public interface MyInterface
{
    void UsefulMethod();
}

public class MyClass : MyInterface
{
    public float variable1;
    public float moreBurden;
    public float thisIsNotRequiredAtAll;

    public void UsefulMethod() {}
    public void AnotherMethod() {}
    public void MoreNoiseMethod() {}
}

public class MyService
{
    private MyClass _myClass;

    public MyService(MyClass myClass)
    {
        _myClass = myClass;
    }

    public void MyOnlyMethod()
    {
        _myClass.UsefulMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您只使用单一方法,但您的服务可以访问大量不必要的信息,从而偏离目标。要创建MyService,其创建者必须能够创建 的实例MyClass

现在图像MyService写成这样

public class MyService
{
    private IMyInterface _myInterface;

    public MyService(IMyInterface myInterface)
    {
        _myInterface = myInterface;
    }
   
    public void MyOnlyMethod()
    {
        _myInterface.UsefulMethod();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,目的_myInterface很明确 - 您只需要方法的特定子集。MyService只能访问该单一方法,并且不会被所有可能的实现细节所干扰。

  • 尽管这一切可能是真的,但我的直觉是你错过了操作问题的要点 (5认同)