键入HttpClient与IHttpClientFactory 键入的客户端指定客户阅读文章很好

问题描述

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

解决方法

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

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

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

键入的客户端

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

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

指定客户

当您需要来自特定客户端的多个实例或需要多个不同的客户端时,此技术会发光。如果您已经注册了多个具有不同名称的不同客户端,则可以通过单个API轻松检索它们。

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

阅读文章很好

,

拥有抽象(即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仅可访问该单一方法,不会因所有可能的实现细节而分心。