WebClientクラスでのCookieContainerの使用


148

以前はHttpWebRequestおよびHttpWebResponseセッションでCookieContainerを使用していましたが、今はWebClientで使用したいと思います。私が理解している限り、HttpWebRequests(request.CookieContainer)のように組み込みのメソッドはありません。CookieContainerでWebClientからCookieを収集するにはどうすればよいですか?

これをググって、次のサンプルを見つけまし

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 2016年

HttpWebRequestクラスは、必要に応じて内部フィールドCookieContainerを使用してm_containerクラスを変更すると思います。
HeartWare 2016

これで十分です!応答からのCookieは自動的にコンテナに追加されます。
lionello

回答:


69

はい。IMHO、GetWebRequest()のオーバーライドは、WebClientの制限された機能に対する最良のソリューションです。このオプションについて知る前に、WebClientが必要なことをほぼ完全にではなくほぼ行っていたため、HttpWebRequestレイヤーに多くの本当に苦痛なコードを記述しました。導出ははるかに簡単です。

もう1つのオプションは、通常のWebClientクラスを使用することですが、要求を行う前に手動でCookieヘッダーを入力し、次に応答でSet-Cookiesヘッダーを引き出します。CookieContainerクラスには、これらのヘッダーの作成と解析を容易にするヘルパーメソッドがあります。それぞれ、CookieContainer.SetCookies()およびCookieContainer.GetCookieHeader()です。

呼び出し元にとってはより簡単であり、2番目のオプションよりも反復コードが少なくて済むため、前者のアプローチを好みます。また、派生アプローチは、複数の拡張性シナリオ(Cookie、プロキシなど)でも同じように機能します。


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

コメントから

「somecookie」の代わりにCookieの名前と値をどのようにフォーマットしますか?

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

複数のCookieの場合:

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

「somecookie」の代わりにCookieの名前と値をどのようにフォーマットしますか?
Neil N

11
@ニールN:wb.Headers.Add(HttpRequestHeader.Cookie、 "cookiename = cookievalue"); 複数のCookieの場合:wb.Headers.Add(HttpRequestHeader.Cookie、 "cookiename1 = cookievalue1; cookiename2 = cookievalue2");
Ian Kemp

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 2014

拡張用のThx。使用するために、公開CookieContainer CookieContainer {get {return _container;を追加します。}セット{_container = value; }}
Igor Shubin

1
@IgorShubinの場合readonlycontainerフィールドの修飾子を削除する必要があります。そうしないと、プロパティに設定できません。コードを変更しました。
hillin 2014

1
Set-Cookie応答ヘッダーをチェックしてはいけませんReadCookiesか?
アキレスは

2
Cookieはコンテナに自動的に追加されるため、実際にはGetWebResponseand は必要ありませんReadCookies
lionello

15

HttpWebRequestは、それに割り当てられたCookieContainerを変更します。返されたCookieを処理する必要はありません。Cookieコンテナをすべての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;
    }
}

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に送信されるWebリクエストはすべて、標準のWebクライアントを含むカスタムWebリクエストの作成者を使用することになります。このアプローチは、すべてのコードに触れる必要がないことを意味します。レジスタープレフィックスを1回呼び出すだけで完了です。「http」プレフィックスを登録して、あらゆる場所でオプトインすることもできます。


最後の2、3の文についてはわかりません。ドキュメントは言う:「のHttpWebRequestクラスは、デフォルトでHTTPとHTTPSスキームのサービス要求に登録されているこれらのスキームのためのさまざまなWebRequestクラスの子孫を登録しようとは失敗します。」
Herohtar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.