Sử dụng CookieContainer với lớp WebClient


148

Trước đây tôi đã sử dụng CookieContainer với các phiên httpWebRequest và HttpWebResponse, nhưng bây giờ, tôi muốn sử dụng nó với WebClient. Theo như tôi hiểu, không có phương thức tích hợp nào giống như đối với HttpWebRequests ( request.CookieContainer). Làm cách nào tôi có thể thu thập cookie từ WebClient trong CookieContainer?

Tôi googled cho điều này và tìm thấy mẫu sau :

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

Đây có phải là cách tốt nhất để làm điều đó?


1
Từ quan điểm của tôi m_containerlà không bao giờ được thiết lập!? Có phải nó luôn trống không?
C4d

Tôi tin rằng lớp HttpWebRequest sửa đổi lớp m_container bằng cách sử dụng trường nội bộ CookieContainer khi cần.
HeartWare

Đây là tất cả những gì bạn cần! Các cookie từ các phản hồi sẽ được thêm vào thùng chứa tự động.
Lionello

Câu trả lời:


69

Đúng. IMHO, ghi đè GetWebRequest () là giải pháp tốt nhất cho chức năng hạn chế của WebClient. Trước khi tôi biết về tùy chọn này, tôi đã viết rất nhiều mã thực sự đau đớn ở lớp HttpWebRequest vì WebClient gần như, nhưng không hoàn toàn, đã làm những gì tôi cần. Đạo hàm dễ hơn nhiều.

Một tùy chọn khác là sử dụng lớp WebClient thông thường, nhưng tự điền tiêu đề Cookie trước khi thực hiện yêu cầu và sau đó rút tiêu đề Set-Cookies về phản hồi. Có các phương thức trợ giúp trên lớp CookieContainer, giúp cho việc tạo và phân tích các tiêu đề này dễ dàng hơn: CookieContainer.SetCookies()CookieContainer.GetCookieHeader(), tương ứng.

Tôi thích cách tiếp cận trước đây vì nó dễ dàng hơn cho người gọi và yêu cầu mã lặp lại ít hơn so với tùy chọn thứ hai. Ngoài ra, cách tiếp cận phái sinh hoạt động theo cùng một cách cho nhiều kịch bản mở rộng (ví dụ: cookie, proxy, v.v.).


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

Từ bình luận

Làm thế nào để bạn định dạng tên và giá trị của cookie thay cho "somecookie"?

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

Đối với nhiều cookie:

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

Làm thế nào để bạn định dạng tên và giá trị của cookie thay cho "somecookie"?
Neil N

11
@Neil N: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename = cookinyue"); Đối với nhiều cookie: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename1 = cookinyue1; cookiename2 = cookinyue2");
Ian Kemp

46

Đây chỉ là phần mở rộng của bài viết bạn tìm thấy.


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
Điều này hoạt động tốt @Pavel, mặc dù bạn có thể cải thiện câu trả lời này bằng cách hiển thị cách sử dụng các tính năng của lớp, đặc biệt là cài đặt và nhận cookie trên đó.
Corgalore

Thx cho gia hạn. Để sử dụng, tôi thêm CookieContainer công khai CookieContainer {get {return _container; } đặt {_container = value; }}
Igor Shubin

1
@IgorShubin bạn phải xóa công cụ readonlysửa đổi của containertrường, nếu không bạn không thể đặt nó trong thuộc tính. Tôi đã sửa đổi mã.
hillin

1
Bạn không nên kiểm tra Set-Cookietiêu đề phản hồi trong ReadCookies?
Achilles

2
Bạn thực sự không cần GetWebResponseReadCookies, vì cookie sẽ tự động được thêm vào thùng chứa.
Lionello

15

HttpWebRequest sửa đổi CookieContainer được gán cho nó. Không cần xử lý cookie trả lại. Chỉ cần chỉ định thùng chứa cookie của bạn cho mọi yêu cầu 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

Tôi nghĩ rằng có cách sạch hơn mà bạn không phải tạo webclient mới (và nó cũng sẽ hoạt động với các thư viện bên thứ 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;
        }
    }
}

Bây giờ tất cả những gì bạn phải làm là chọn tham gia vào những tên miền bạn muốn sử dụng:

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

Điều đó có nghĩa là BẤT K web webrequest nào đi đến example.com bây giờ sẽ sử dụng trình tạo webrequest tùy chỉnh của bạn, bao gồm cả webclient tiêu chuẩn. Cách tiếp cận này có nghĩa là bạn không phải chạm vào tất cả các mã của bạn. Bạn chỉ cần gọi tiền tố đăng ký một lần và được thực hiện với nó. Bạn cũng có thể đăng ký tiền tố "http" để chọn mọi thứ ở mọi nơi.


Tôi không chắc chắn về vài câu cuối cùng; các tài liệu nói: "Theo mặc định, lớp HTTPWebRequest được đăng ký cho các yêu cầu dịch vụ cho các lược đồ HTTP và HTTPS. Cố gắng đăng ký một hậu duệ WebRequest khác cho các lược đồ này sẽ thất bại."
Herohtar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.