System.Net.Http.HttpClient i System.Net.Http.HttpClientHandler w .NET Framework 4.5 implementują IDisposable (przez System.Net.Http.HttpMessageInvoker ).
Dokumentacja using
oświadczenia mówi:
Z reguły, gdy używasz obiektu IDisposable, powinieneś zadeklarować go i utworzyć jego instancję w instrukcji using.
Ta odpowiedź wykorzystuje ten wzorzec:
var baseAddress = new Uri("http://example.com");
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler() { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler) { BaseAddress = baseAddress })
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("foo", "bar"),
new KeyValuePair<string, string>("baz", "bazinga"),
});
cookieContainer.Add(baseAddress, new Cookie("CookieName", "cookie_value"));
var result = client.PostAsync("/test", content).Result;
result.EnsureSuccessStatusCode();
}
Ale najbardziej widoczne przykłady firmy Microsoft nie wywołują Dispose()
ani jawnie, ani niejawnie. Na przykład:
- Oryginalny artykuł napisany ogłaszając wypuścić z HttpClient.
- Rzeczywista dokumentacja MSDN dla HttpClient.
- BingTranslateSample
- GoogleMapsSample
- WorldBankSample
W zapowiedź „s komentarze, ktoś poprosił pracownika firmy Microsoft:
Po sprawdzeniu próbek zauważyłem, że nie wykonałeś operacji usuwania na instancji HttpClient. Użyłem wszystkich wystąpień HttpClient z użyciem instrukcji w mojej aplikacji i pomyślałem, że jest to właściwy sposób, ponieważ HttpClient implementuje interfejs IDisposable. Czy jestem na dobrej drodze?
Jego odpowiedź brzmiała:
Zasadniczo jest to poprawne, chociaż trzeba uważać na „używanie” i asynchronizację, ponieważ tak naprawdę nie mieszają się one w .Net 4, w .Net 4.5 można użyć „czekaj” wewnątrz instrukcji „using”.
Przy okazji, możesz ponownie użyć tego samego klienta HttpClient tyle razy, ile chcesz, więc zazwyczaj nie będziesz ich tworzyć / usuwać przez cały czas.
Drugi akapit jest zbędny w stosunku do tego pytania, które nie martwi się, ile razy można użyć instancji HttpClient, ale o tym, czy konieczne jest usunięcie go, gdy już go nie potrzebujesz.
(Aktualizacja: w rzeczywistości ten drugi akapit jest kluczem do odpowiedzi, jak podano poniżej przez @DPeden.)
Więc moje pytania to:
Czy w obecnej wersji (.NET Framework 4.5) konieczne jest wywołanie metody Dispose () w instancjach HttpClient i HttpClientHandler? Wyjaśnienie: przez „konieczne” mam na myśli, jeśli istnieją negatywne konsekwencje braku wyrzucenia, takie jak wyciek zasobów lub ryzyko uszkodzenia danych.
Jeśli nie jest to konieczne, czy byłaby to „dobra praktyka”, ponieważ implementują one IDisposable?
Jeśli jest to konieczne (lub zalecane), czy wspomniany powyżej kod bezpiecznie go implementuje (dla .NET Framework 4.5)?
Jeśli te klasy nie wymagają wywołania Dispose (), dlaczego zostały zaimplementowane jako IDisposable?
Jeśli wymagają lub jeśli jest to zalecana praktyka, czy przykłady Microsoft wprowadzają w błąd lub są niebezpieczne?
źródło
Flush
jeden po każdym zapisie, a poza niedogodnościami związanymi z utrzymywaniem podstawowych zasobów dłużej niż to konieczne, co się nie stanie, co jest wymagane do „prawidłowego zachowania”?Odpowiedzi:
Ogólny konsensus jest taki, że nie trzeba (nie należy) pozbywać się HttpClient.
Stwierdzało to wiele osób, które są ściśle zaangażowane w sposób, w jaki działa.
Zobacz post na blogu Darrel Miller i powiązany post SO: Przeszukiwanie HttpClient powoduje wyciek pamięci w celach informacyjnych.
Zdecydowanie sugeruję również przeczytanie rozdziału HttpClient z Projektowanie ewoluowalnych interfejsów API sieci Web za pomocą programu ASP.NET, aby uzyskać kontekst na temat tego, co dzieje się pod maską, szczególnie cytowany tutaj rozdział „Cykl życia”:
Lub nawet otwórz DotPeek.
źródło
Timeout
nieruchomości nie będą się ze sobą tupać?Obecne odpowiedzi są nieco mylące i wprowadzające w błąd i brakuje im ważnych implikacji DNS. Spróbuję podsumować, gdzie wszystko jest jasne.
IDisposable
obiektów powinna być najlepiej utylizowana, gdy z nimi skończysz , szczególnie te, które posiadają nazwane / współdzielone zasoby systemu operacyjnego .HttpClient
nie jest wyjątkiem, ponieważ jak zauważa Darrel Miller , alokuje tokeny anulowania, a ciała żądania / odpowiedzi mogą być niezarządzanymi strumieniami.Connection:close
nagłówek po zmianach DNS. Inna możliwość polega na recyklinguHttpClient
po stronie klienta, albo okresowo, albo poprzez jakiś mechanizm, który uczy się o zmianie DNS. Aby uzyskać więcej informacji, zobacz https://github.com/dotnet/corefx/issues/11224 (sugeruję uważne przeczytanie go przed ślepym użyciem kodu sugerowanego w linkowanym blogu).źródło
W moim rozumieniu, wywołanie
Dispose()
jest konieczne tylko wtedy, gdy blokuje zasoby, których potrzebujesz później (jak określone połączenie). Zawsze zaleca się uwolnienie zasobów, których już nie używasz, nawet jeśli nie będziesz ich ponownie potrzebować, po prostu dlatego, że zasadniczo nie powinieneś trzymać się zasobów, których nie używasz (zamierzona gra słów).Przykład Microsoftu niekoniecznie jest niepoprawny. Wszystkie używane zasoby zostaną zwolnione po zamknięciu aplikacji. I w przypadku tego przykładu dzieje się to prawie natychmiast po zakończeniu
HttpClient
używania. W podobnych przypadkach jawne wywoływanieDispose()
jest nieco zbędne.Ale generalnie, kiedy klasa implementuje
IDisposable
, zrozumienie jest takie, że powinieneśDispose()
o jej wystąpieniach, gdy tylko będziesz w pełni gotowy i zdolny. Sądzę, że jest to szczególnie prawdziwe w przypadkach, wHttpClient
których nie jest wyraźnie udokumentowane, czy zasoby lub połączenia są utrzymywane / otwarte. W przypadku, gdy połączenie zostanie ponownie wykorzystane [wkrótce], będziesz chciał zrezygnowaćDipose()
z niego - w tym przypadku nie jesteś „w pełni gotowy”.Zobacz także: IDisposable.Dispose Metoda i kiedy należy wywołać Dispose
źródło
Dispose()
go przedwcześnie i musisz połączyć się kilka sekund później, jeśli istniejące połączenie może być ponownie użyte. Podobnie, nie chcesz niepotrzebnieDispose()
obrazów lub innych struktur, które możesz odbudować w ciągu minuty lub dwóch.Dispose () wywołuje poniższy kod, który zamyka połączenia otwarte przez instancję HttpClient. Kod został stworzony przez dekompilację za pomocą dotPeek.
HttpClientHandler.cs - Usuń
Jeśli nie wywołasz usuwania, ServicePointManager.MaxServicePointIdleTime, który działa według timera, zamknie połączenia http. Domyślna wartość to 100 sekund.
ServicePointManager.cs
Jeśli czas bezczynności nie został ustawiony na nieskończoność, wydaje się bezpieczne, aby nie wywoływać usuwania i pozwolić, aby licznik czasu bezczynności uruchamiał się i zamykał połączenia dla ciebie, chociaż lepiej byłoby, gdybyś zadzwonił do usuwania w instrukcji użycia, jeśli wiesz, że masz już instancję HttpClient i szybciej zwalniasz zasoby.
źródło
Krótka odpowiedź: Nie, stwierdzenie w obecnie akceptowanej odpowiedzi NIE JEST dokładne : „Ogólny konsensus jest taki, że nie musisz (nie powinieneś) pozbywać się HttpClient”.
Długa odpowiedź : ZARÓWNO następujące stwierdzenia są prawdziwe i możliwe do osiągnięcia w tym samym czasie:
IDisposable
Obiekt ma / zaleca się być utylizowane.I NIE KONIECZNIE SĄ KONFLIKTOWANE. Jest to tylko kwestia tego, jak zorganizujesz swój kod, aby ponownie wykorzystać
HttpClient
ORAZ nadal go poprawnie usuwać.Jeszcze dłuższa odpowiedź cytowana z mojej innej odpowiedzi :
To nie jest przypadek, aby zobaczyć ludzi w niektórych blogach obwiniając jak
HttpClient
„sIDisposable
interfejs sprawia, że mają tendencję do korzystania zusing (var client = new HttpClient()) {...}
wzorca, a następnie doprowadzić do wyczerpania problemu handler gniazdo.Uważam, że sprowadza się to do niewypowiedzianej (błędnej?) Koncepcji: „oczekuje się, że obiekt IDisposable będzie krótkotrwały” .
JEDNAK, choć na pewno wygląda to na coś krótkotrwałego, gdy piszemy kod w tym stylu:
Oficjalna dokumentacja IDisposable nie wspomina
IDisposable
obiekty mają być krótkotrwałe. Z definicji IDisposable jest jedynie mechanizmem umożliwiającym uwolnienie niezarządzanych zasobów. Nic więcej. W tym sensie OCZEKUJESZ, że ostatecznie doprowadzisz do usunięcia, ale nie wymaga to, abyś zrobił to w krótkim czasie.Dlatego Twoim zadaniem jest właściwy wybór momentu uruchomienia usuwania, w oparciu o wymagania dotyczące cyklu życia Twojego obiektu. Nic nie stoi na przeszkodzie, abyś mógł używać IDisposable w długim okresie:
Dzięki temu nowemu zrozumieniu, teraz ponownie odwiedzamy ten post na blogu , możemy wyraźnie zauważyć, że „poprawka” inicjuje się
HttpClient
raz, ale nigdy go nie usuwa, dlatego z jego danych wyjściowych netstat wynika, że połączenie pozostaje w stanie USTALONYM, co oznacza, że ma NIE zostało poprawnie zamknięte. Gdyby był zamknięty, jego stanem byłby TIME_WAIT. W praktyce nie jest wielkim problemem wyciek tylko jednego połączenia otwartego po zakończeniu całego programu, a plakat na blogu nadal widzi wzrost wydajności po poprawce; ale obwinianie IDisposable i wybieranie NIE wyrzucania go jest koncepcyjnie niepoprawne.źródło
HttpClient.Dispose
?.HttpClient client
zmiennej, co jest rzeczą Programowania-101, którą prawdopodobnie i tak już robisz. Możesz nawet nadal móc z niego korzystaćusing (...) {...}
. Na przykład zobacz przykład Hello World w mojej odpowiedzi.Ponieważ nie wydaje się, aby ktokolwiek tutaj o tym wspominał, nowym najlepszym sposobem zarządzania HttpClient i HttpClientHandler w .Net Core 2.1 jest użycie HttpClientFactory .
Rozwiązuje większość wyżej wymienionych problemów i problemów w czysty i łatwy w użyciu sposób. Ze wspaniałego postu na blogu Steve'a Gordona :
Dodaj następujące pakiety do projektu .Net Core (2.1.1 lub nowszy):
Dodaj to do Startup.cs:
Wstrzyknąć i użyć:
Przejrzyj serię postów na blogu Steve'a, aby uzyskać o wiele więcej funkcji.
źródło
W moim przypadku tworzyłem HttpClient w metodzie, która faktycznie wykonała wywołanie usługi. Coś jak:
W roli pracownika Azure, po wielokrotnym wywoływaniu tej metody (bez pozbywania się HttpClient), ostatecznie nie powiedzie się
SocketException
(próba połączenia nie powiodła się).Zrobiłem HttpClient zmienną instancji (usuwając ją na poziomie klasy) i problem zniknął. Powiedziałbym więc, tak, pozbyć się HttpClient, zakładając, że jest bezpieczny (nie masz zaległych połączeń asynchronicznych), aby to zrobić.
źródło
W typowym użyciu (odpowiedzi <2 GB) nie trzeba usuwać wiadomości HttpResponseMessages.
Zwracane typy metod HttpClient powinny zostać usunięte, jeśli ich zawartość strumienia nie jest w pełni odczytana. W przeciwnym razie CLR nie będzie wiedział, że te strumienie mogą zostać zamknięte, dopóki nie zostaną usunięte.
Jeśli ustawisz HttpCompletionOption na ResponseHeadersRead lub odpowiedź jest większa niż 2 GB, powinieneś posprzątać. Można to zrobić, wywołując Dispose w HttpResponseMessage lub wywołując Dispose / Close w strumieniu uzyskanym z HttpResonseMessage Content lub całkowicie czytając treść.
To, czy zadzwonisz Dispose na HttpClient, zależy od tego, czy chcesz anulować oczekujące żądania, czy nie.
źródło
Jeśli chcesz pozbyć się HttpClient, możesz to zrobić, jeśli skonfigurujesz go jako pulę zasobów. Na koniec aplikacji pozbywasz się puli zasobów.
Kod:
var handler = HttpClientHander.GetHttpClientHandle (nowy Uri („podstawowy adres URL”)).
źródło
Dispose
metodę zarejestrowaną w GC. To powinno być ocenione wyżej na górze.Zastosowanie wstrzykiwania zależności w konstruktorze ułatwia zarządzanie czasem życia urządzenia
HttpClient
- eliminuje konieczność zarządzania czasem życia poza kodem, który go potrzebuje, i ułatwia jego zmianę w późniejszym terminie.Moje obecne preferencje to utworzenie oddzielnej klasy klienta HTTP, która dziedziczy
HttpClient
po raz na docelową domenę punktu końcowego, a następnie uczynienie z niej singletonu przy użyciu wstrzykiwania zależności.public class ExampleHttpClient : HttpClient { ... }
Następnie biorę zależność od konstruktora od niestandardowego klienta HTTP w klasach usług, w których potrzebuję dostępu do tego interfejsu API. Rozwiązuje to problem związany z czasem życia i ma zalety, jeśli chodzi o pule połączeń.
Możesz zobaczyć działający przykład w pokrewnej odpowiedzi na https://stackoverflow.com/a/50238944/3140853
źródło
Przeczytaj moją odpowiedź na bardzo podobne pytanie zamieszczone poniżej. Powinno być jasne, że należy traktować
HttpClient
instancje jako singletony i ponownie wykorzystywać w żądaniach.Jaki jest narzut związany z tworzeniem nowego HttpClient dla każdego połączenia w kliencie WebAPI?
źródło
Myślę, że należy użyć wzorca singletonu, aby uniknąć konieczności tworzenia instancji HttpClient i zamykania go przez cały czas. Jeśli używasz .Net 4.0, możesz użyć przykładowego kodu jak poniżej. Aby uzyskać więcej informacji na temat wzoru singletonu, sprawdź tutaj .
Użyj kodu jak poniżej.
źródło