Spóźniam się na przyjęcie, ale oto moja podróż edukacyjna na ten trudny temat.
1. Gdzie możemy znaleźć oficjalnego rzecznika ponownego użycia HttpClient?
Mam na myśli, że jeśli ponowne użycie HttpClient jest zamierzone
i jest to ważne , taki adwokat jest lepiej udokumentowany we własnej dokumentacji API, zamiast ukrywać się w wielu „Zaawansowanych tematach”, „Wzorcu (anty)” lub innych postach na blogu . W przeciwnym razie skąd nowy uczeń powinien to wiedzieć, zanim będzie za późno?
Na dzień dzisiejszy (maj 2018 r.) Pierwszy wynik wyszukiwania w Google „c # httpclient” wskazuje na tę stronę referencyjną interfejsu API w witrynie MSDN , która wcale nie wspomina o tej intencji. Lekcja 1 dla początkujących polega na tym, że zawsze kliknij link „Inne wersje” tuż za nagłówkiem strony pomocy MSDN, prawdopodobnie znajdziesz tam linki do „bieżącej wersji”. W tym przypadku HttpClient przeniesie Cię do najnowszego dokumentu
zawierającego opis tego zamiaru .
Podejrzewam, że wielu programistów, którzy byli nowi w tym temacie, również nie znalazło właściwej strony z dokumentacją, dlatego ta wiedza nie jest szeroko rozpowszechniona, a ludzie byli zaskoczeni, gdy odkryli ją
później , być może w trudny sposób .
2. (Nie?) Koncepcja using
IDisposable
Ten jest nieco nie na temat, ale nadal warto podkreślić, że nie jest to przypadek, aby zobaczyć ludzi w tych wspomnianych blogach obwiniając jak HttpClient
„s IDisposable
interfejs sprawia, że mają tendencję do korzystania z using (var client = new HttpClient()) {...}
wzorca, a następnie doprowadzić do problemu.
Uważam, że sprowadza się to do niewypowiedzianej (błędnej?) Koncepcji:
„oczekuje się, że obiekt IDisposable będzie krótkotrwały” .
JEDNAK, chociaż na pewno wygląda to na coś krótkotrwałego, gdy piszemy kod w tym stylu:
using (var foo = new SomeDisposableObject())
{
...
}
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:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
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, aby przeciekać tylko jedno połączenie otwarte po zakończeniu całego programu, a plakat na blogu nadal widzi wzrost wydajności po poprawce; ale nadal koncepcyjnie niewłaściwe jest obwinianie IDisposable i NIE wyrzucanie go.
3. Czy musimy umieścić HttpClient we właściwości statycznej, czy nawet jako singleton?
Na podstawie zrozumienia poprzedniej części myślę, że odpowiedź tutaj jest jasna: „niekoniecznie”. To naprawdę zależy od tego, jak zorganizujesz swój kod, pod warunkiem, że użyjesz HttpClient ORAZ (najlepiej) ostatecznie go usuniesz.
Zabawne jest, że nawet przykład w
sekcji Uwagi w obecnym oficjalnym dokumencie
nie ma racji. Definiuje klasę „GoodController”, zawierającą statyczną właściwość HttpClient, która nie będzie usuwana; co nie zgadza się z tym, co
podkreśla inny przykład w sekcji Przykłady : „trzeba zadzwonić do dysponowania ... aby aplikacja nie przeciekała zasobów”.
I wreszcie singleton nie jest pozbawiony własnych wyzwań.
„Ile osób uważa, że zmienna globalna jest dobrym pomysłem? Nikt.
Ile osób uważa singleton za dobry pomysł? Kilka.
Co daje? Singletony to tylko garść zmiennych globalnych. ”
- Cytat z tego inspirującego przemówienia „Global State and Singletons”
PS: SqlConnection
Ten jest nieistotny dla obecnych pytań i odpowiedzi, ale prawdopodobnie jest dobrze znany. Wzorzec użycia SqlConnection jest inny. Państwo nie ma potrzeby ponownego użycia SqlConnection , ponieważ będzie ona obsługiwać jego puli połączeń lepiej.
Różnica wynika z ich podejścia do wdrożenia. Każda instancja HttpClient korzysta z własnej puli połączeń (cytowanej
tutaj ); ale zgodnie z tym SqlConnection jest zarządzany przez centralną pulę połączeń .
I nadal musisz pozbyć się SqlConnection, tak jak powinieneś zrobić dla HttpClient.