2009-11-21 5 views
126

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

Я googled для этого и нашел the following sample:

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' никогда не установлен !? Разве это всегда пусто? – C4u

+0

Я считаю, что класс HttpWebRequest модифицирует класс m_container, используя его внутреннее поле CookieContainer по мере необходимости. – HeartWare

+0

Это все, что вам нужно! Куки из ответов будут автоматически добавлены в контейнер. – lionello

ответ

66

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

Другой вариант - использовать обычный класс WebClient, но вручную заполнить заголовок Cookie перед тем, как сделать запрос, а затем вытащить заголовок Set-Cookies в ответ. В классе CookieContainer есть вспомогательные методы, которые упрощают создание и анализ этих заголовков: CookieContainer.SetCookies() и CookieContainer.GetCookieHeader() соответственно.

Я предпочитаю прежний подход, так как это проще для вызывающего абонента и требует менее повторяющегося кода, чем второй вариант. Кроме того, подход деривации работает одинаково для нескольких сценариев расширяемости (например, файлы cookie, прокси и т. Д.).

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

От Комментарии

Как отформатировать имя и значение куки вместо «somecookie»?

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

Для несколько печенья:

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

Как вы отформатируете имя и значение cookie вместо «somecookie»? –

+10

@Neil N: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename = cookievalue"); Для нескольких файлов cookie: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename1 = cookievalue1; cookiename2 = cookievalue2"); –

+0

Ян, редактирование ответа - лучший выбор. Я сделал это – razon

42

Это один просто продолжение статьи вы нашли.


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

+0

Thx для расширения. Для его использования я добавляю public CookieContainer CookieContainer { get {return _container; } set {_container = value; } } –

+1

@IgorShubin вам нужно удалить модификатор 'readonly' поля' container', иначе вы не можете его установить в свойстве. Я изменил код. – hillin

6

Я думаю, что есть способ очистки, где вам не нужно создавать новый WebClient (и он будет работать с библиотеками 3 участника, а)

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

это означает, что ЛЮБОЙ WebRequest, который идет на example.com будет использовать свой обычай WebRequest творца, включая стандартный WebClient. Этот подход означает, что вам не нужно касаться всего кода. Вы просто вызываете префикс регистра один раз и выполняете его. Вы также можете зарегистрироваться для префикса «http», чтобы выбрать везде и везде.

7

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