Utilizzo di CookieContainer con classe WebClient


148

In precedenza ho usato un CookieContainer con sessioni HttpWebRequest e HttpWebResponse, ma ora voglio usarlo con un WebClient. A quanto ho capito, non esiste un metodo integrato come per HttpWebRequests ( request.CookieContainer). Come posso raccogliere i cookie da un client Web in un cookieContainer?

Ho cercato su Google per questo e ho trovato il seguente esempio :

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;
    }
}

È questo il modo migliore per farlo?


1
Dal mio punto di vista m_containernon è mai impostato !? Non è sempre vuoto?
C4d

Credo che la classe HttpWebRequest modifica la classe m_container usando il suo campo interno CookieContainer secondo necessità.
HeartWare,

Questo è tutto ciò di cui hai bisogno! I cookie delle risposte verranno aggiunti automaticamente al contenitore.
Lionello,

Risposte:


69

Sì. IMHO, ignorando GetWebRequest () è la migliore soluzione alla funzionalità limitata di WebClient. Prima di conoscere questa opzione, ho scritto un sacco di codice davvero doloroso a livello di HttpWebRequest perché WebClient ha quasi fatto, ma non del tutto, ciò di cui avevo bisogno. La derivazione è molto più semplice.

Un'altra opzione è quella di utilizzare la normale classe WebClient, ma popolare manualmente l'intestazione Cookie prima di effettuare la richiesta e quindi estrarre l'intestazione Set-Cookies sulla risposta. Esistono metodi di supporto nella classe CookieContainer che semplificano la creazione e l'analisi di queste intestazioni: CookieContainer.SetCookies()e CookieContainer.GetCookieHeader(), rispettivamente.

Preferisco il primo approccio poiché è più facile per il chiamante e richiede un codice meno ripetitivo rispetto alla seconda opzione. Inoltre, l'approccio di derivazione funziona allo stesso modo per più scenari di estensibilità (ad es. Cookie, proxy, ecc.).


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

Dai commenti

Come si formatta il nome e il valore del cookie al posto di "somecookie"?

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

Per più cookie:

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

Come si formatta il nome e il valore del cookie al posto di "somecookie"?
Neil N

11
@Neil N: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename = cookievalue"); Per più cookie: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename1 = cookievalue1; cookiename2 = cookievalue2");
Ian Kemp,

46

Questa è solo l'estensione dell'articolo che hai trovato.


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
Questo ha funzionato bene @Pavel, sebbene tu possa migliorare questa risposta mostrando come usare le funzionalità della classe, specialmente impostando e inserendo i cookie su di essa.
Corgalore,

Grazie per l'estensione. Per usarlo aggiungo CookieContainer pubblico CookieContainer {get {return _container; } set {_container = value; }}
Igor Shubin,

1
@IgorShubin devi rimuovere il readonlymodificatore del containercampo, altrimenti non puoi impostarlo nella proprietà. Ho modificato il codice.
Hillin

1
Non dovresti controllare l' Set-Cookieintestazione della risposta in ReadCookies?
Achille,

2
In realtà non è necessario il GetWebResponsee ReadCookies, poiché i cookie verranno aggiunti automaticamente al contenitore.
Lionello,

15

HttpWebRequest modifica il CookieContainer assegnato ad esso. Non è necessario elaborare i cookie restituiti. Basta assegnare il contenitore dei cookie a ogni richiesta Web.

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

Penso che ci sia un modo più pulito in cui non è necessario creare un nuovo client Web (e funzionerà anche con librerie di terze parti)

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;
        }
    }
}

Ora tutto ciò che devi fare è optare per quali domini vuoi usare questo:

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

Ciò significa che QUALUNQUE richiesta web che va a example.com ora utilizzerà il tuo creatore di richieste web personalizzato, incluso il client web standard. Questo approccio significa che non devi toccare tutto il codice. Basta chiamare il prefisso del registro una volta e averlo finito. Puoi anche registrarti per il prefisso "http" per optare per tutto ovunque.


Non sono sicuro dell'ultima coppia di frasi; i documenti dicono: "La classe HttpWebRequest è registrata per soddisfare le richieste di servizio per gli schemi HTTP e HTTPS per impostazione predefinita. I tentativi di registrare un discendente WebRequest diverso per questi schemi falliranno."
Herohtar,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.