Używanie CookieContainer z klasą WebClient


148

Wcześniej użyłem CookieContainer z sesjami HttpWebRequest i HttpWebResponse, ale teraz chcę go używać z WebClient. O ile rozumiem, nie ma wbudowanej metody, takiej jak w przypadku HttpWebRequests ( request.CookieContainer). Jak mogę zbierać pliki cookie z WebClient w CookieContainer?

I googled to i znaleźć następujące próbki :

public class CookieAwareWebClient : WebClient
{
    private readonly CookieContainer m_container = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);
        HttpWebRequest webRequest = request as HttpWebRequest;
        if (webRequest != null)
        {
            webRequest.CookieContainer = m_container;
        }
        return request;
    }
}

Czy to najlepszy sposób na zrobienie tego?


1
Z mojego punktu widzenia m_containernigdy nie jest ustawione !? Czy to nie zawsze jest puste?
C4d

Uważam, że klasa HttpWebRequest modyfikuje klasę m_container przy użyciu jej wewnętrznego pola CookieContainer w razie potrzeby.
HeartWare

To wszystko, czego potrzebujesz! Pliki cookie z odpowiedzi zostaną automatycznie dodane do kontenera.
lionello

Odpowiedzi:


69

Tak. IMHO, przesłanianie GetWebRequest () jest najlepszym rozwiązaniem ograniczonej funkcjonalności WebClienta. Zanim dowiedziałem się o tej opcji, napisałem wiele naprawdę bolesnego kodu w warstwie HttpWebRequest, ponieważ WebClient prawie, ale nie do końca, zrobił to, czego potrzebowałem. Wyprowadzenie jest znacznie łatwiejsze.

Inną opcją jest użycie zwykłej klasy WebClient, ale ręczne wypełnienie nagłówka Cookie przed wysłaniem żądania, a następnie wyciągnięcie nagłówka Set-Cookies z odpowiedzi. W klasie CookieContainer istnieją metody pomocnicze, które ułatwiają tworzenie i analizowanie tych nagłówków: CookieContainer.SetCookies()i CookieContainer.GetCookieHeader(), odpowiednio.

Wolę to pierwsze podejście, ponieważ jest łatwiejsze dla dzwoniącego i wymaga mniej powtarzalnego kodu niż druga opcja. Ponadto metoda wyprowadzania działa w ten sam sposób w przypadku wielu scenariuszy rozszerzalności (np. Pliki cookie, serwery proxy itp.).


118
 WebClient wb = new WebClient();
 wb.Headers.Add(HttpRequestHeader.Cookie, "somecookie");

Z komentarzy

Jak sformatować nazwę i wartość pliku cookie zamiast „somecookie”?

wb.Headers.Add(HttpRequestHeader.Cookie, "cookiename=cookievalue"); 

W przypadku wielu plików cookie:

wb.Headers.Add(HttpRequestHeader.Cookie, 
              "cookiename1=cookievalue1;" +
              "cookiename2=cookievalue2");

Jak sformatować nazwę i wartość pliku cookie zamiast „somecookie”?
Neil N,

11
@Neil N: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename = cookievalue"); W przypadku wielu plików cookie: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename1 = cookievalue1; cookiename2 = cookievalue2");
Ian Kemp

46

Ten jest tylko rozszerzeniem znalezionego artykułu.


public class WebClientEx : WebClient
{
    public WebClientEx(CookieContainer container)
    {
        this.container = container;
    }

    public CookieContainer CookieContainer
        {
            get { return container; }
            set { container= value; }
        }

    private CookieContainer container = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest r = base.GetWebRequest(address);
        var request = r as HttpWebRequest;
        if (request != null)
        {
            request.CookieContainer = container;
        }
        return r;
    }

    protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result)
    {
        WebResponse response = base.GetWebResponse(request, result);
        ReadCookies(response);
        return response;
    }

    protected override WebResponse GetWebResponse(WebRequest request)
    {
        WebResponse response = base.GetWebResponse(request);
        ReadCookies(response);
        return response;
    }

    private void ReadCookies(WebResponse r)
    {
        var response = r as HttpWebResponse;
        if (response != null)
        {
            CookieCollection cookies = response.Cookies;
            container.Add(cookies);
        }
    }
}

3
To zadziałało dobrze @Pavel, chociaż możesz ulepszyć tę odpowiedź, pokazując, jak korzystać z funkcji klasy, zwłaszcza ustawiania i pobierania plików cookie.
Corgalore

Dzięki za przedłużenie. Aby z niego skorzystać, dodaję public CookieContainer CookieContainer {get {return _container; } set {_container = wartość; }}
Igor Shubin

1
@IgorShubin musisz usunąć readonlymodyfikator containerpola, w przeciwnym razie nie możesz go ustawić we właściwości. Zmodyfikowałem kod.
hillin

1
Nie powinieneś sprawdzać Set-Cookienagłówka odpowiedzi ReadCookies?
Achilles

2
W rzeczywistości nie potrzebujesz GetWebResponsei ReadCookies, ponieważ pliki cookie zostaną automatycznie dodane do kontenera.
lionello

15

HttpWebRequest modyfikuje przypisaną do niego CookieContainer. Nie ma potrzeby przetwarzania zwróconych plików cookie. Po prostu przypisz swój kontener cookie do każdego żądania internetowego.

public class CookieAwareWebClient : WebClient
{
    public CookieContainer CookieContainer { get; set; } = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri uri)
    {
        WebRequest request = base.GetWebRequest(uri);
        if (request is HttpWebRequest)
        {
            (request as HttpWebRequest).CookieContainer = CookieContainer;
        }
        return request;
    }
}

6

Myślę, że istnieje bardziej przejrzysty sposób, w którym nie musisz tworzyć nowego klienta internetowego (i będzie działać również z bibliotekami innych firm)

internal static class MyWebRequestCreator
{
    private static IWebRequestCreate myCreator;

    public static IWebRequestCreate MyHttp
    {
        get
        {
            if (myCreator == null)
            {
                myCreator = new MyHttpRequestCreator();
            }
            return myCreator;
        }
    }

    private class MyHttpRequestCreator : IWebRequestCreate
    {
        public WebRequest Create(Uri uri)
        {
            var req = System.Net.WebRequest.CreateHttp(uri);
            req.CookieContainer = new CookieContainer();
            return req;
        }
    }
}

Teraz wszystko, co musisz zrobić, to wybrać domeny, których chcesz używać:

    WebRequest.RegisterPrefix("http://example.com/", MyWebRequestCreator.MyHttp);

Oznacza to, że KAŻDE zapytanie internetowe, które trafia do example.com, będzie teraz używać Twojego niestandardowego kreatora zapytań internetowych, w tym standardowego klienta internetowego. Takie podejście oznacza, że ​​nie musisz dotykać całego kodu. Wystarczy raz wywołać prefiks rejestru i skończyć z tym. Możesz także zarejestrować prefiks „http”, aby akceptować wszystko wszędzie.


Nie jestem pewien co do ostatnich kilku zdań; w dokumentacji jest napisane : „Klasa HttpWebRequest jest domyślnie zarejestrowana do obsługi żądań obsługi schematów HTTP i HTTPS. Próby zarejestrowania innego elementu podrzędnego WebRequest dla tych schematów zakończą się niepowodzeniem”.
Herohtar
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.