Usando CookieContainer com class WebClient

Eu usei anteriormente um CookieContainer com sessões HttpWebRequest e HttpWebResponse, mas agora, eu quero usá-lo com um WebClient. Tanto quanto eu entendo, não há nenhum método embutido como existe para HttpWebRequests ( request.CookieContainer ). Como posso coletar cookies de um WebClient em um CookieContainer?

Eu pesquisei por isso e encontrei o seguinte exemplo :

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

Esse é o melhor jeito de fazer isso?

Sim. IMHO, substituindo GetWebRequest () é a melhor solução para a funcionalidade limitada do WebClient. Antes que eu soubesse sobre essa opção, escrevi muitos códigos realmente dolorosos na camada HttpWebRequest porque o WebClient quase, mas não completamente, fez o que eu precisava. Derivação é muito mais fácil.

Outra opção é usar a class WebClient regular, mas preencher manualmente o header Cookie antes de fazer a solicitação e, em seguida, extrair o header Set-Cookies na resposta. Existem methods auxiliares na class CookieContainer que facilitam a criação e a análise desses headers: CookieContainer.SetCookies() e CookieContainer.GetCookieHeader() , respectivamente.

Eu prefiro a primeira abordagem, uma vez que é mais fácil para o chamador e requer menos código repetitivo do que a segunda opção. Além disso, a abordagem de derivação funciona da mesma maneira para vários cenários de extensibilidade (por exemplo, cookies, proxies, etc.).

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

Comentários

Como você formata o nome e valor do cookie no lugar de “somecookie”?

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

Para vários cookies:

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

Este é apenas a extensão do artigo que você encontrou.

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

O HttpWebRequest modifica o CookieContainer atribuído a ele. Não há necessidade de processar cookies devolvidos. Basta atribuir seu contêiner de cookies a todas as solicitações da 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; } } 

Acho que há uma maneira mais limpa em que você não precisa criar um novo cliente da Web (e também funciona com bibliotecas de terceiros)

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

Agora tudo o que você precisa fazer é optar por quais domínios você deseja usar isto:

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

Isso significa que QUALQUER pedido da Web que vai para o example.com agora usará seu criador de solicitações da Web personalizado, incluindo o padrão do webclient. Essa abordagem significa que você não precisa tocar em todos os códigos. Você apenas chama o prefixo de registro uma vez e termina com ele. Você também pode se inscrever no prefixo “http” para optar por tudo em qualquer lugar.