J'ai déjà utilisé un CookieContainer avec les sessions HttpWebRequest et HttpWebResponse, mais je souhaite maintenant l'utiliser avec un WebClient. Pour autant que je sache, il n’existe pas de méthode intégrée comme celle de HttpWebRequests (request.CookieContainer
). Comment puis-je collecter des cookies d'un Web Client dans un CookieContainer?
Je googlé pour cela et trouvé l'exemple suivant :
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;
}
}
Est-ce la meilleure façon de le faire?
Oui. IMHO, surcharger GetWebRequest () est la meilleure solution à la fonctionnalité limitée de WebClient. Avant de connaître cette option, j’ai écrit beaucoup de code très pénible au niveau de la couche HttpWebRequest parce que WebClient a presque, mais pas tout à fait, fait ce qu’il me fallait. La dérivation est beaucoup plus facile.
Une autre option consiste à utiliser la classe WebClient standard, mais à renseigner manuellement l'en-tête Cookie avant de faire la demande, puis à extraire l'en-tête Set-Cookies de la réponse. Il existe des méthodes d'assistance sur la classe CookieContainer qui facilitent la création et l'analyse de ces en-têtes: CookieContainer.SetCookies()
et CookieContainer.GetCookieHeader()
, respectivement.
Je préfère la première approche car elle est plus facile pour l'appelant et nécessite moins de code répétitif que la deuxième option. En outre, l’approche de dérivation fonctionne de la même manière pour plusieurs scénarios d’extensibilité (par exemple, les cookies, les mandataires, etc.).
WebClient wb = new WebClient();
wb.Headers.Add(HttpRequestHeader.Cookie, "somecookie");
à partir de commentaires
Comment formater le nom et la valeur du cookie à la place de "somecookie"?
wb.Headers.Add(HttpRequestHeader.Cookie, "cookiename=cookievalue");
Pour plusieurs cookies:
wb.Headers.Add(HttpRequestHeader.Cookie,
"cookiename1=cookievalue1;" +
"cookiename2=cookievalue2");
Celui-ci est juste une extension de l'article que vous avez trouvé.
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);
}
}
}
HttpWebRequest modifie le CookieContainer qui lui est attribué. Il n'est pas nécessaire de traiter les cookies retournés. Attribuez simplement votre conteneur de cookies à chaque demande 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;
}
}
Je pense qu'il y a une manière plus propre de ne pas créer un nouveau client Web (et que cela fonctionnera également avec les bibliothèques tierces)
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;
}
}
}
Il ne vous reste plus qu'à choisir les domaines dans lesquels vous souhaitez utiliser ceci:
WebRequest.RegisterPrefix("http://example.com/", MyWebRequestCreator.MyHttp);
Cela signifie que TOUT webrequest envoyé à example.com utilisera désormais votre créateur de webrequest personnalisé, y compris le client Web standard. Cette approche signifie que vous n'avez pas à toucher tout votre code. Vous n'avez qu'à appeler le préfixe du registre une fois et en finir. Vous pouvez également vous inscrire pour le préfixe "http" afin que tout soit activé partout.