ใช้ CookieContainer กับคลาส WebClient


148

ก่อนหน้านี้ฉันเคยใช้ CookieContainer กับเซสชัน HttpWebRequest และ HttpWebResponse แต่ตอนนี้ฉันต้องการใช้กับ WebClient เท่าที่ฉันเข้าใจไม่มีวิธีการในตัวเช่นเดียวกับ HttpWebRequests ( request.CookieContainer) ฉันจะรวบรวมคุกกี้จาก WebClient ใน CookieContainer ได้อย่างไร

ฉัน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
จากมุมมองของฉันm_containerไม่เคยตั้งค่า! มันว่างเปล่าใช่ไหม
C4d

ฉันเชื่อว่าคลาส HttpWebRequest แก้ไขคลาส m_container โดยใช้ฟิลด์ภายใน CookieContainer ตามต้องการ
HeartWare

นี่คือทั้งหมดที่คุณต้องการ! คุกกี้จากคำตอบจะถูกเพิ่มลงในคอนเทนเนอร์โดยอัตโนมัติ
lionello

คำตอบ:


69

ใช่. IMHO การเอาชนะ GetWebRequest () เป็นทางออกที่ดีที่สุดในการ จำกัด การใช้งานของ WebClient ก่อนที่ฉันจะรู้เกี่ยวกับตัวเลือกนี้ฉันได้เขียนรหัสที่เจ็บปวดจริงๆที่เลเยอร์ HttpWebRequest เพราะ WebClient เกือบ แต่ไม่ได้ทำสิ่งที่ฉันต้องการ การได้มานั้นง่ายกว่ามาก

อีกตัวเลือกหนึ่งคือการใช้คลาส WebClient ปกติ แต่เติมส่วนหัวคุกกี้ด้วยตนเองก่อนทำการร้องขอจากนั้นดึงส่วนหัว Set-Cookies ออกมาตอบสนอง มีวิธีการช่วยเหลือในคลาส CookieContainer ซึ่งทำให้การสร้างและการแยกส่วนหัวเหล่านี้ง่ายขึ้น: CookieContainer.SetCookies()และCookieContainer.GetCookieHeader()ตามลำดับ

ฉันชอบวิธีการแบบเดิมเนื่องจากผู้โทรง่ายกว่าและต้องใช้รหัสซ้ำน้อยกว่าตัวเลือกที่สอง นอกจากนี้วิธีการสืบทอดยังทำงานในลักษณะเดียวกันสำหรับสถานการณ์การขยายความสามารถหลายอย่าง (เช่นคุกกี้พร็อกซี ฯลฯ )


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

จากความคิดเห็น

คุณจัดรูปแบบชื่อและค่าของคุกกี้แทน "somecookie" อย่างไร

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

สำหรับคุกกี้หลายรายการ:

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

คุณจัดรูปแบบชื่อและค่าของคุกกี้แทน "somecookie" ได้อย่างไร
Neil N

11
@Neil N: wb.Headers.Add (HttpRequestHeader.Cookie, "cookiename = cookievalue"); สำหรับคุกกี้หลายรายการ: 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 แม้ว่าคุณจะสามารถปรับปรุงคำตอบนี้ได้โดยแสดงวิธีใช้คุณสมบัติของชั้นเรียนโดยเฉพาะการตั้งค่าและรับคุกกี้บนมัน
Corgalore

ขอบคุณสำหรับการขยาย สำหรับการใช้งานฉันเพิ่มสาธารณะ CookieContainer CookieContainer {รับ {return _container; } set {_container = value; }}
Igor Shubin

1
@IgorShubin คุณต้องลบreadonlyตัวดัดแปลงของcontainerฟิลด์มิฉะนั้นคุณไม่สามารถตั้งค่าในคุณสมบัติ ฉันแก้ไขรหัส
hillin

1
คุณไม่ควรตรวจสอบSet-Cookieหัวข้อการตอบสนองReadCookiesหรือไม่
Achilles

2
คุณไม่จำเป็นต้องใช้GetWebResponseและReadCookiesเนื่องจากคุกกี้จะถูกเพิ่มลงในคอนเทนเนอร์โดยอัตโนมัติ
lionello

15

HttpWebRequest แก้ไข CookieContainer ที่กำหนดให้ ไม่จำเป็นต้องประมวลผลคุกกี้ที่ส่งคืน เพียงกำหนดคอนเทนเนอร์คุกกี้ของคุณให้กับทุกคำขอทางเว็บ

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

ฉันคิดว่ามันมีวิธีที่สะอาดกว่าที่คุณไม่ต้องสร้าง webclient ใหม่ (และมันจะใช้ได้กับไลบรารี่ของบุคคลที่สามด้วย)

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

นั่นหมายความว่า webrequest ใด ๆ ที่ไปที่ example.com จะใช้ผู้สร้าง webrequest ที่คุณกำหนดเองรวมถึง webclient มาตรฐาน วิธีการนี้หมายความว่าคุณไม่จำเป็นต้องแตะรหัสทั้งหมด คุณเพียงแค่เรียกคำนำหน้าการลงทะเบียนหนึ่งครั้งและดำเนินการให้เสร็จ คุณสามารถลงทะเบียนสำหรับคำนำหน้า "http" เพื่อเลือกใช้สำหรับทุกสิ่งได้ทุกที่


ฉันไม่แน่ใจเกี่ยวกับประโยคสองประโยคสุดท้าย; เอกสารกล่าวว่า"คลาส HttpWebRequest มีการลงทะเบียนเพื่อขอรับบริการสำหรับ HTTP และ HTTPS รูปแบบโดยค่าเริ่มต้นความพยายามที่จะลงทะเบียนเป็นลูกหลาน WebRequest แตกต่างกันสำหรับรูปแบบเหล่านี้จะล้มเหลว.."
Herohtar
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.