【问题标题】:Typed HttpClient vs IHttpClientFactory类型化 HttpClient 与 IHttpClientFactory
【发布时间】:2020-10-09 19:15:58
【问题描述】:

以下2种设置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>();

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();
```

【问题讨论】:

标签: c# asp.net-core dotnet-httpclient httpclientfactory


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    我认为最大的不同是从消费的角度来看。

    类型化客户端

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

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

    命名客户

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

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

    好读的文章

    【讨论】:

      【解决方案3】:

      拥有抽象(即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();
          }
      }
      

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

      现在图片MyService 写成这样

      public class MyService
      {
          private IMyInterface _myInterface;
      
          public MyService(IMyInterface myInterface)
          {
              _myInterface = myInterface;
          }
         
          public void MyOnlyMethod()
          {
              _myInterface.UsefulMethod();
          }
      }
      

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

      【讨论】:

      • 虽然这一切可能都是真的,但我的直觉是你错过了操作问题的重点
      • 是的,我错了,我错过了 IHttpClientFactory 而不是 IHttpClient...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多