Використання CookieContainer з класом WebClient


148

Раніше я використовував CookieContainer з сесіями HttpWebRequest і HttpWebResponse, але тепер я хочу використовувати його з WebClient. Наскільки я розумію, немає вбудованого методу, як для HttpWebRequests (request.CookieContainer ). Як я можу збирати файли cookie з WebClient у CookieContainer?

Я погуглився для цього і знайшов наступний зразок :

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

Це найкращий спосіб зробити це?


1
З моєї точки зору, m_containerце ніколи не встановлюється !? Хіба це завжди порожньо?
C4d

Я вважаю, що клас HttpWebRequest змінює клас m_container, використовуючи його внутрішнє поле CookieContainer за потребою.
HeartWare

Це все, що вам потрібно! Файли cookie з відповідей будуть додані до контейнера автоматично.
ліонелло

Відповіді:


69

Так. IMHO, переосмислення GetWebRequest () є найкращим рішенням обмеженої функціональності WebClient. Перш ніж я дізнався про цей варіант, я написав багато дійсно болісного коду на шарі HttpWebRequest, оскільки WebClient майже, але не зовсім робив те, що мені потрібно. Виведення набагато простіше.

Інший варіант - використовувати звичайний клас WebClient, але вручну заповнити заголовок Cookie перед тим, як зробити запит, а потім витягнути заголовок Set-Cookies на відповідь. Для класу CookieContainer є допоміжні методи, які спрощують створення та аналіз цих заголовків: CookieContainer.SetCookies()і CookieContainer.GetCookieHeader(), відповідно.

Я віддаю перевагу колишньому підходу, оскільки він простіше для абонента і вимагає менш повторюваного коду, ніж другий варіант. Також підхід до деривації працює аналогічно для декількох сценаріїв розширення (наприклад, файли cookie, проксі-сервери тощо).


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

З коментарів

Як ви відформатуєте ім'я та значення файлу cookie замість "somecookie"?

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

Для декількох файлів cookie:

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

Як ви відформатуєте ім'я та значення файлу cookie замість "somecookie"?
Ніл N

11
@Neil N: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename = cookievalue"); Для декількох файлів cookie: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename1 = cookievalue1; cookiename2 = cookievalue2");
Ян Кемп

46

Це лише розширення статті, яку ви знайшли.


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
@Pavel це добре працювало, хоча ви могли б покращити цю відповідь, показавши, як використовувати функції класу, особливо налаштування та отримання файлів cookie на ньому.
Corgalore

Thx для розширення. Для його використання я додаю публічний CookieContainer CookieContainer {get {return _container; } встановити {_container = значення; }}
Ігор Шубін

1
@IgorShubin вам потрібно буде видалити readonlyмодифікатор containerполя, інакше ви не можете встановити його у властивості. Я змінив код.
hillin

1
Чи не слід перевірити Set-Cookieзаголовок відповіді ReadCookies?
Ахілл

2
Насправді вам GetWebResponseі не потрібно ReadCookies, оскільки файли cookie будуть додані до контейнера автоматично.
Ліонелло

15

HttpWebRequest змінює призначений йому CookieContainer. Немає необхідності обробляти повернені файли cookie. Просто призначіть контейнер cookie кожному веб-запиту.

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

Я думаю, що є більш чіткий спосіб, коли вам не потрібно створювати новий веб-кліент (і він також буде працювати з сторонніми бібліотеками)

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

Тепер все, що вам потрібно зробити, це вибрати, для яких доменів ви хочете використовувати це:

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

Це означає, що будь-який веб-запит, який переходить на example.com, тепер використовуватиме ваш користувальницький веб-запит, включаючи стандартний webclient. Такий підхід означає, що вам не доведеться торкатися всього коду. Ви просто зателефонуєте до префіксу реєстру один раз і зробите це з ним. Ви також можете зареєструвати префікс "http", щоб увімкнути все, що скрізь.


Я не впевнений у останніх кількох реченнях; що документи говорять: «Клас HttpWebRequest зареєстрований для обслуговування запитів по HTTP і HTTPS схеми за замовчуванням Спроби зареєструвати інший WebRequest нащадок цих схеми зазнають невдачі.» .
Герохтар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.