4

Я создаю экземпляр HttpClient для каждого отдельного API, с которым работает мое веб-приложение.Управление несколькими экземплярами HttpClient с использованием Injection Dependency

Я хочу использовать инъекцию зависимостей с SimpleInjector, чтобы ввести HttpClient в бизнес-классы. Например, у меня есть ITwitterBusiness и IInstagramBusiness, и оба они принимают HttpClient в своем конструкторе.

Какова наилучшая практика регистрации нескольких объектов одного и того же типа с использованием Injection Dependency?

Я уверен, что часть проблемы может быть моей конструкцией, но вот некоторые идеи.

Моя первая идея состоит в том, чтобы использовать делегат при регистрации DI

container.Register<ITwitterBusiness>(() => new TwitterBusiness(httpClientTwitter)); 

кажется достаточно простым, но я не знаю, если этот метод имеет какие-либо плохие побочные эффекты, например, делая SimpleInjector работать медленнее или если я нарушаю шаблон дизайна.

Моя вторая идея заключается в том, чтобы использовать инъекцию на основе контекстаhttp://simpleinjector.readthedocs.io/en/latest/advanced.html#context-based-injection

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

Мне очень любопытно, могу ли я решить это чисто по дизайну. Например, создавая фиктивные классы. Я просто не нашел хороших примеров, но если я правильно понял, то мог бы создать фиктивные классы, такие как HttpClientTwitter, который наследует HttpClient, и таким образом я могу избавиться от неоднозначной регистрации.

Спасибо!

ответ

3

Моя первая идея - использовать делегата в регистрации DI. Кажется достаточно простым, но я не знаю, есть ли у этого метода какие-либо плохие побочные эффекты, например, заставляя SimpleInjector работать медленнее или если я нарушаю некоторые шаблоны проектирования.

Рекомендуется использовать автоматическую проводку (напротив регистрации делегата) в случае, если тип имеет какие-либо компоненты приложения, которые необходимо подключить. Автоматическая проводка упрощает регистрацию и позволяет Simple Injector анализировать граф объектов. Оба, похоже, не имеют никакого отношения к вашему делу. HttpClient - не компонент приложения, а тип инфраструктуры. Кажется, что нет других зависимостей, поэтому регистрация делегата не создает проблем с ремонтопригодностью.

Регистрация делегатов медленнее по сравнению с использованием автоматической проводки, простой инжектор не в состоянии оптимизировать работу с помощью делегатов. Однако очень важно, чтобы вы заметили какую-либо разницу в производительности при этом. Это не то, о чем вам следует беспокоиться.

Моя вторая идея - использовать инъекцию на основе контекста. Я считаю, что это позволит мне ввести определенный экземпляр HttpClient в определенный класс. Все еще не совсем точно, как это работает.

Вы можете сделать отличную регистрацию на основе контекста.Например:

var httpClientTwitterRegistration = Lifestyle.Transient.CreateRegistration<HttpClient>(
    () => new HttpClient("https://twitter"), 
    container); 

container.RegisterConditional(typeof(HttpClient), httpClientTwitterRegistration, 
    c => c.Consumer.ImplementationType == typeof(TwitterBusiness)); 

var httpClientInstagramRegistration = Lifestyle.Transient.CreateRegistration<HttpClient>(
    () => new HttpClient("https://instagram"), 
    container); 

container.RegisterConditional(typeof(HttpClient), httpClientInstagramRegistration, 
    c => c.Consumer.ImplementationType == typeof(InstagramBusiness)); 

Мне очень интересно, если я мог бы решить эту проблему чисто по дизайну

путем введения HttpClient в TwitterBusiness класса вы получаете ложное чувство гибкости. Кажется, что у вас есть две реализации swap, но так как HttpClient - это конкретный тип, изменение реализаций не имеет смысла. Поскольку TwitterBusiness напрямую связывается с HttpClient, это должно быть сделано с детальностью реализации. Другими словами, переместите создание HttpContext внутри TwitterBusiness. Любые аргументы, которые вам нужно настроить (возможно, URL), можно ввести в TwitterBusiness. Таким образом, TwitterBusiness полностью контролирует создание и удаление HttpClient, и вы вводите единственное, что интересно изменить (url).

+1

Спасибо, Стивен. Я забыл упомянуть, что все экземпляры HttpClient являются одноточечными, поэтому экземпляр HttpClient Twitter будет повторно использоваться с жизнью приложения. Я всегда стараюсь избегать статических переменных, но, я думаю, я мог бы использовать его как статическую переменную внутри TwitterBusiness и инициализировать ее только один раз, если в конструкторе нет значения. Как вы думаете? Для модульного тестирования я мог передать HttpMessageHandler конструктору. – raRaRa

+0

@raRaRa вы даже можете зарегистрировать свой TwitterBusiness как singleton, если он не имеет гражданства (что обычно требуется). Это означает, что ваш httpclient все еще может быть переменной экземпляра, но я не думаю, что HttpClient является потокобезопасным. Поэтому создание его внутри каждого mrthod было бы безопаснее. – Steven

+0

Он потокобезопасен и должен быть использован как можно больше. Вот почему я хочу, чтобы он был одиночным. В противном случае я бы просто создал экземпляр HttpClient по запросу в TwitterBusiness. Но вы определенно правы, TwitterBusiness может быть зарегистрирован как singleton. Я собираюсь обдумать это и попытаюсь придумать решение. Спасибо за помощь! :) – raRaRa

Смежные вопросы