WebClient CookieContainer хорошо работает в .NET 4.0+, но не в более ранних версиях.

Я разрабатываю приложение, которое использует WebClient. У меня есть этот класс, который расширяет основные функции WebClient:

public class WebClientEx : WebClient
{
    private CookieContainer _cookieContainer = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);
        if (request is HttpWebRequest)
        {
            (request as HttpWebRequest).CookieContainer = _cookieContainer;
            (request as HttpWebRequest).AllowAutoRedirect = true;
            (request as HttpWebRequest).Timeout = 10000;
        }
        return request;
    }
}

Я использую WebClientEx для входа на сайт и запроса некоторой информации. Это хорошо работает для 4.0 и 4.5, но не работает в более ранних версиях, таких как 3.5, 3.0 и т. д. Я добавил код отладки, и в ранних версиях он говорит, что в контейнере cookie 0 файлов cookie, а 4.0+ говорит, что есть две куки, как и должно быть.

Так что причина, вероятно, в том, что в ранних версиях .NET Framework есть некоторые проблемы с хранением файлов cookie в контейнере файлов cookie. Как это исправить?


person Uhehesh    schedule 19.08.2012    source источник
comment
Ответ на ваш вопрос можно найти здесь - stackoverflow.com /вопросы/1777221/   -  person dana    schedule 20.08.2012
comment
Кто-нибудь поможет или я должен использовать более простое решение без расширения WebClient?   -  person Uhehesh    schedule 21.08.2012
comment
Мои тесты показывают, что этот класс работает так, как ожидалось. Возможно, вы могли бы объяснить немного больше, почему вы считаете, что это не работает.   -  person dana    schedule 22.08.2012


Ответы (2)


Я подтвердил, что поведение .NET 3.5 отличается от .NET 4.0. Для тестирования используется следующий код:

Uri sourceUri = new Uri(@"http://www.html-kit.com/tools/cookietester/");
WebClientEx webClientEx = new WebClientEx();
webClientEx.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
webClientEx.UploadString(sourceUri, "cn=MyCookieName&cv=MyCookieValue");
var text = webClientEx.DownloadString(sourceUri);
var doc = new HtmlAgilityPack.HtmlDocument();
doc.Load(new MemoryStream(Encoding.ASCII.GetBytes((text))));
var node = doc.DocumentNode.SelectNodes("//div").Single(n => n.InnerText.StartsWith("\r\nNumber of cookies received:"));
Debug.Assert(int.Parse(node.InnerText.Split(' ')[4]) == 1);

Конечно, это не отвечает на ваш вопрос; но я не вижу причин, по которым существует разница в поведении, кроме как сказать, что, возможно, это было исправлено в .NET 4.0, а исправление не было добавлено в .NET 3.5 или более ранние версии.

Я попробовал то же самое с HttpWebRequest и столкнулся с той же проблемой (работает в 4, но не раньше):

HttpWebRequest webreq = ((HttpWebRequest) (WebRequest.Create(sourceUri)));
CookieContainer cookies = new CookieContainer();

var postdata = Encoding.ASCII.GetBytes("cn=MyCookieName&cv=MyCookieValue");

webreq.CookieContainer = cookies;
webreq.Method = "POST";
webreq.ContentLength = postdata.Length;
webreq.ContentType = "application/x-www-form-urlencoded";

Stream webstream = webreq.GetRequestStream();
webstream.Write(postdata, 0, postdata.Length);
webstream.Close();

using (WebResponse response = webreq.GetResponse())
{
    webstream = response.GetResponseStream();
    using (StreamReader reader = new StreamReader(webstream))
    {
        String responseFromServer = reader.ReadToEnd();
        var doc = new HtmlAgilityPack.HtmlDocument();
        doc.Load(new MemoryStream(Encoding.ASCII.GetBytes((responseFromServer))));
        var node =
            doc.DocumentNode.SelectNodes("//div").Single(n => n.InnerText.StartsWith("\r\nNumber of cookies received:"));
        Debug.Assert(int.Parse(node.InnerText.Split(' ')[4]) == 1);
    }
}

Итак, похоже, проблема с HttpWebRequest (который использует WebClient). Это может быть новым, потому что я видел, как люди использовали подобный код до выпуска 4.0 (может быть, до 3.50, и они говорят, что это работало).

Если это срочно, я бы посоветовал обратиться в службу поддержки Microsoft. Если у вас есть лицензия MSDN, по следующей ссылке подробно описано, как сделать запрос в службу поддержки с включенными билетами поддержки MSDN: http://msdn.microsoft.com/en-us/subscriptions/bb266240.aspx Если у вас нет MSDN, вы можете обратиться в службу поддержки, как описано здесь: https://support.microsoft.com/oas/default.aspx?Gprid=8291&st=1&wfxredirect=1&sd=gn

если это менее срочно, вы, вероятно, могли бы зарегистрировать проблему на странице http://connect.microsoft.com/VisualStudio чтобы увидеть, получите ли вы ответ с обходными путями.

person Peter Ritchie    schedule 27.08.2012
comment
Может быть, я просто попробую другое, более простое решение (настолько плохо, что я должен использовать плохие решения из-за ошибок). Если у меня будет свободное время, я опубликую сообщение об ошибке, но я думаю, что они знают об этом. ИМО больше никто не ответит, поэтому я дам вам +50... - person Uhehesh; 27.08.2012

Я только что создал базовый IHttpHandler для тестирования этого класса, и, похоже, он работает.

<%@ WebHandler Language="C#" Class="CookieTest" %>

using System;
using System.Net;
using System.Web;

public class CookieTest : IHttpHandler
{
    public class WebClientEx : WebClient
    {
        private CookieContainer _cookieContainer = new CookieContainer();

        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest request = base.GetWebRequest(address);
            if (request is HttpWebRequest)
            {
                (request as HttpWebRequest).CookieContainer = _cookieContainer;
                (request as HttpWebRequest).AllowAutoRedirect = true;
                (request as HttpWebRequest).Timeout = 10000;
            }
            return request;
        }
    }

    public void ProcessRequest(HttpContext ctxt)
    {
        ctxt.Response.ContentType = "text/plain";

        String cmd = ctxt.Request["cmd"];
        if (cmd == "set")
        {
            ctxt.Response.Cookies.Add(new HttpCookie("test", "test"));
            ctxt.Response.Write("Cookie Set: test = test");
        }
        else if (cmd == "get")
        {
            ctxt.Response.Write("Cookie Value: test = " + ctxt.Request.Cookies["test"].Value);
        }
        else
        {
            // run out tests
            WebClientEx wc = new WebClientEx();

            ctxt.Response.Write("Running tests on .NET version: " + Environment.Version);
            ctxt.Response.Write(Environment.NewLine + Environment.NewLine);
            ctxt.Response.Write("Setting Cookie...");
            ctxt.Response.Write(Environment.NewLine + Environment.NewLine);
            ctxt.Response.Write("Response: " + wc.DownloadString(ctxt.Request.Url.AbsoluteUri + "?cmd=set"));
            ctxt.Response.Write(Environment.NewLine + Environment.NewLine);
            ctxt.Response.Write("Getting Cookie...");
            ctxt.Response.Write(Environment.NewLine + Environment.NewLine);
            ctxt.Response.Write("Response: " + wc.DownloadString(ctxt.Request.Url.AbsoluteUri + "?cmd=get"));
            ctxt.Response.Write(Environment.NewLine + Environment.NewLine);
        }
    }

    public bool IsReusable
    {
        get { return true; }
    }
}

Результаты, которые я получаю:

Выполнение тестов на версии .NET: 2.0.50727.5456

Установка файла cookie...

Ответ: Набор файлов cookie: тест = тест

Получение печенья...

Ответ: Значение файла cookie: тест = тест

Вам это кажется правильным?

person dana    schedule 21.08.2012
comment
Я собираюсь проверить это сейчас. Вероятно, проблема в настройках моего проекта. - person Uhehesh; 22.08.2012
comment
Ваш код мне совсем не помог, потому что это код ASP.NET, а у меня только C# для Windows. Пробовал снова сделать проект и импортировать в него код, но результат все тот же. - person Uhehesh; 22.08.2012
comment
@Uhehesh - Причина, по которой я использовал ASP.NET, заключается в том, что я смог реализовать как (а) клиент, так и (б) сервер в небольшом объеме кода. Я мог бы рассказать вам, как настроить это на вашем компьютере, если вам интересно. Однако мне было интересно, не могли бы вы предоставить более подробную информацию о том, какое тестирование/отладку вы сделали, что заставляет вас думать, что этот класс не работает. - person dana; 22.08.2012
comment
Хорошо, я понимаю это. Но, как я уже сказал, я добавил некоторый код для отладки, и он сказал, что в GetWebRequest 0 куки в 1.0-3.5, в то время как он сказал 2 куки (как и должно быть) в 4.0 и 4.5. - person Uhehesh; 22.08.2012
comment
Если вы не можете предоставить более подробную информацию о том, как вы тестируете свой код (может быть, пример того, как вы его используете), я, к сожалению, не могу больше помочь. Извиняюсь. - person dana; 22.08.2012