Использование CookieContainer с классом WebClient
Ранее я использовал CookieContainer с сеансами HttpWebRequest и HttpWebResponse, но теперь я хочу использовать его с WebClient. Насколько я понимаю, нет встроенного метода, например, для HttpWebRequests (request.CookieContainer
). Как я могу собирать файлы cookie из WebClient в CookieContainer?
I googled для этого и нашел следующий пример
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
Да. IMHO, переопределение GetWebRequest() - лучшее решение для ограниченной функциональности WebClient. Прежде чем я узнал об этом варианте, я написал много очень мучительного кода на уровне HttpWebRequest, потому что WebClient почти, но не совсем, сделал то, что мне было нужно. Вывод намного проще.
Другой вариант - использовать обычный класс WebClient, но вручную заполнять заголовок Cookie перед тем, как сделать запрос, а затем вытащить заголовок Set-Cookies в ответ. В классе CookieContainer есть вспомогательные методы, которые облегчают создание и анализ этих заголовков: CookieContainer.SetCookies()
и CookieContainer.GetCookieHeader()
, соответственно.
Я предпочитаю прежний подход, так как это проще для вызывающего и требует менее повторяющегося кода, чем второй вариант. Кроме того, подход деривации работает одинаково для нескольких сценариев расширяемости (например, файлы cookie, прокси и т.д.).
Ответ 2
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");
Ответ 3
Это просто расширение статьи, которую вы нашли.
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);
}
}
}
Ответ 4
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;
}
}
Ответ 5
Я думаю, что там более чистый способ, когда вам не нужно создавать новый веб-клиент (и он будет работать и с сторонними библиотеками)
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, теперь будет использовать ваш собственный создатель webrequest, включая стандартный веб-клиент. Этот подход означает, что вам не нужно касаться всего кода. Вы просто вызываете префикс регистра один раз и выполняете его.
Вы также можете зарегистрироваться для префикса "http", чтобы выбрать все для всех.