Типизированный 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();
```

person Ivan Studenikin    schedule 09.10.2020    source источник
comment
Отвечает ли это на ваш вопрос? HttpClientFactory.Create против нового HttpClient   -  person Julian    schedule 09.10.2020
comment
@ Джулиан, нет, раз уж речь идет о старом HttpFactory   -  person Ivan Studenikin    schedule 13.10.2020


Ответы (3)


ИМО, пойду попутно HttpClient. Причины в том,

  1. Принцип KISS. CatalogService действительно нужен HttpClient. Сервис не заботится о том, как получить клиента.
  2. Single Responsibility Principle (SRP) - Say tomorrow you have to keep two instances of CatalogService to send requests to two different endpoints,
    • You can pass in a IHttpClientFactory and implement routing inside CatalogService, but that breaks SRP.
    • Или вы можете создать CatalogServiceFactory. Эта фабрика получает IHttpClientFactory и реализует внутри маршрутизацию. Это также известно как разделение проблем.
person Han Zhao    schedule 10.10.2020

Думаю, самая большая разница проявляется, если посмотреть на них с точки зрения потребления.

Типизированный клиент

Вы получите HttpClient экземпляр, который, возможно, был украшен некоторой устойчивой стратегией против временного сбоя и некоторыми значениями по умолчанию. Вы даже можете получить клиента, у которого уже установлен BaseUrl.

Таким образом, этот подход может быть особенно полезен, если вам нужно спрятать клиент REST API за строго типизированным уровнем сервиса.

Именованный клиент

Этот метод может пригодиться, когда вам нужно несколько экземпляров от конкретного клиента или когда вам нужно несколько разных клиентов. Если вы зарегистрировали несколько разных клиентов с разными именами, вы можете легко получить их через один API.

Таким образом, этот подход может быть полезен, если вам нужно вызвать разные нижестоящие системы и вам нужно агрегировать их результаты.

Хорошо читать статьи

person Peter Csala    schedule 12.10.2020

Наличие абстракции (т.е. 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 имеет доступ только к этому единственному методу и не отвлекается на все возможные детали реализации.

person tsvedas    schedule 09.10.2020
comment
Хотя все это может быть правдой, я чувствую, что вы упустили суть вопроса об операциях - person TheGeneral; 10.10.2020
comment
Ага, моя ошибка, я пропустил это IHttpClientFactory не _2 _... - person tsvedas; 10.10.2020