Образ жизни HttpClient в MVC4 с использованием Castle-Windsor
В веб-запросе я хочу сделать звонок на другой сервер, используя Microsoft HttpClient. Я использую MVC4 (размещенный в IIS) и Castle-Windsor в качестве IOC-контейнера. Я прочитал, что HttpClient предназначен для жизни во время нескольких вызовов, и мой вопрос заключается в том, как мне это реализовать.
Я придумываю несколько вариантов:
- Не обращайте внимания на тот факт, что HttpClient предназначен для нескольких вызовов, и создавайте новый каждый раз, когда он мне нужен.
- Создайте объект Singleton (стиль жизни в замке), который хранит HttpClient между вызовами. Есть ли риски с этим? Будет ли производительность плохой, если несколько веб-запросов используют один и тот же HTTP-клиент?
Есть ли лучший способ сделать это?
2 ответа
Я хотел бы использовать LifestyleTransient
создать новый для каждого запроса. Это безопаснее всего, когда вы не уверены, что класс может функционировать как одиночка.
Также неплохо полагаться на абстракцию (интерфейс), а не на HttpClient напрямую, если вы не уверены, что класс никогда не будет использоваться отдельно от выполнения HTTP-запросов. Даже тогда это может облегчить модульное тестирование. Это одно из больших преимуществ использования Windsor или другого DI-контейнера. В противном случае не так уж много пользы от простого создания экземпляра HttpClient
прямо в вашем классе.
Обновить. Я немного посмотрел и нашел этот ответ, указывающий, что HttpClient
должен быть повторно использован для данного API. За него проголосовали, и я не вижу никакого инакомыслия в опыте (или иным образом), поэтому я буду ссылаться на него при ближайшем развитии.
Я бы реализовал это, определив строго типизированный клиентский класс, который реализует интерфейс, и затем в зависимости от интерфейса в моих классах (не непосредственно на клиенте.) Затем Windsor может создать класс для интерфейса и поддерживать его как одноэлементный.
По умолчанию, если вы создаете новый экземпляр HttpClient для каждого вызова, каждый вызов создает новое TCP-соединение, что приводит к задержке и снижению пропускной способности. Если вы хотите иметь новый экземпляр HttpClient, потому что он содержит данные для каждого вызова, то вы можете иметь одноэлементный HttpClientHandler, передать его в ctor HttpClient, и он будет использовать TCP-соединения для всех экземпляров HttpClient.
Скотт, вот три подхода, которые мы использовали в этой работе. Надеюсь, это поможет, я новичок в stackru, поэтому не могу опубликовать более двух ссылок, по-видимому.
1) Просто установите статический / одиночный HttpClient и передайте все заголовки для каждого вызова с помощью HttpRequestMessage, как описано здесь
2) Имейте статический / одноэлементный WebRequest|HttpClientHandler и передайте его в Ctor HttpClient с disposeHandler, установленным в false.
3) В некоторых случаях у нас была библиотека инструментария DelegatingHandler, которую нужно было утилизировать после каждого вызова HttpClient. Поэтому мы создали WebRequestHandler, который ничего не делает в Dispose(), как показано ниже, передали его в ctor DelegatingHandler, а затем передали DelegatingHandler в ctor HttpClient с disposeHandler, для которого установлено значение false.
public class LongLivedWebRequestHandler : WebRequestHandler
{
public override void Dispose()
{
// Do nothing...
}
}