Является ли жизнеспособным / поточно-ориентированным использование статического HttpClient в блоке using? - PullRequest
0 голосов
/ 15 мая 2019

Скажем, у меня есть контроллер с методом Index(), и этот контроллер использует несколько «классов менеджера», которые управляют определенными активами, которые необходимо получить с помощью HttpClient из API.

I 'мы читали, что совместное использование HttpClient с несколькими вызовами лучше, чем повторная его установка при каждом вызове для сохранения портов.

Однако я хочу избавиться от HttpClient до того, как контроллер вернет представление, потому чтопредставление содержит весь внешний интерфейсный проект на основе Knockout / Typescript, который обрабатывает остальные данные (так что это в основном только настройки и метаданные).

Нужно ли передавать переменную HttpClient всем и каждому«Класс менеджера», или достаточно сделать что-то вроде следующего и использовать статический HttpClient внутри классов?

public ActionResult Index()
{
  using (Globals.Client = new System.Net.Http.HttpClient())
  {
    // do stuff like SettingManager.GetSetting("settingKey") which uses 
    // the Globals.Client variable
  }
  return View();
}

Или я даже не хочу располагать HttpClient впервое место?

1 Ответ

1 голос
/ 15 мая 2019

Одним из решений является создание отдельной зависимости, отвечающей за управление HttpClient. Это имеет побочное преимущество, так как позволяет вашим контроллерам не зависеть напрямую от HttpClient. Любой класс, который зависит от HttpClient, становится сложнее для тестирования. Это также проблема обслуживания, потому что если вы хотите изменить поведение, вы должны изменить его повсюду. Представьте себе, если вы когда-нибудь решите, что все, что вы получаете от этого HttpClient, может быть кэшировано? Вам придется изменить это во многих классах.

Вы можете определить абстракцию и реализацию следующим образом:

public interface IDoesSomething
{
    string GetSetting(string key);
}

public class HttpClientDoesSomething : IDoesSomething, IDisposable
{
    private readonly HttpClient _client;
    private readonly string _apiUrl;

    public HttpClientDoesSomething(string apiUrl)
    {
        _client = new HttpClient();
        _apiUrl = apiUrl;
    }

    public string GetSetting(string key)
    {
        // use the client to retrieve the setting
    }

    public void Dispose()
    {
        _client?.Dispose();
    }
}

Теперь проблема удалена из вашего контроллера, потому что вы вводите интерфейс:

public class MyController : Controller
{
    private readonly IDoesSomething _doesSomething;

    public MyController(IDoesSomething doesSomething)
    {
        _doesSomething = doesSomething;
    }

    public ActionResult Index()
    {
        var setting = _doesSomething.GetSetting("whatever"); 
        // whatever else this does.
        return View();
    }
}

Теперь в вашей загрузочной конфигурации вы можете зарегистрировать HttpClientDoesSomething как синглтон:

services.AddSingleton<IDoesSomething>(new HttpClientDoesSomething("url from settings"));

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

...