Невозможно получить cookie с помощью WebClient

Поправьте меня, если я ошибаюсь в своих мыслях.

Насколько я понимаю, любой новый экземпляр класса WebClient начнет новый сеанс, генерируя новый идентификатор сеанса.

Чтобы предотвратить это, я должен получить идентификатор сеанса при первом использовании, а затем передать его всем новым экземплярам WebClients. (Для метода "GET" просто можно добавить в запрос как любой другой параметр)

Теоретически это можно сделать с помощью класса, например:

public class ExtendedWebClient : WebClient
{
    public CookieContainer CookieContainer { get; private set; }

    [SecuritySafeCritical]
    public ExtendedWebClient()
    {
        this.CookieContainer = new CookieContainer();
    }

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);

        if (request is HttpWebRequest)
            (request as HttpWebRequest).CookieContainer = this.CookieContainer;

        return request;
    }
}

Однако это не работает с jsessionid cookie, у этого подхода есть две проблемы.

  1. Я не вижу значение jsessionid в сохраненном CookieContainer.
  2. Даже если я получу это значение с использованием другого подхода, например, нижеприведенного, а затем добавлю это значение в URI запроса как & jsessionid = someValue, это не поможет.

Я проверял несколько раз, и каждый раз, когда я отправляю такой запрос в Windows Phone, ответ имеет другой уникальный идентификатор jsessionid.

Однако, если я напишу такой запрос в браузере, ответ вернется с правильным jsessionid.


Следующий код позволяет получить значение jsessionid из ответа в Windows Phone (использует HttpWebRequest вместо WebClient), но не решает проблему:

                        // working with some uri
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
                        request.Method = "GET";
                        request.CookieContainer = new CookieContainer();
                        request.BeginGetResponse(asynchronousResult =>
                            {
                                try
                                {
                                    using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult))
                                    {
                                        CookieCollection cookies = response.Cookies;
                                        foreach (Cookie c in cookies)
                                        {
                                            if (c.Name == "JSESSIONID")
                                                // jsessionid value is here. Can be saved & stored somewhere
                                        }
                                        response.Close();
                                    }


                                catch (Exception e)
                                {
                                    // handling exception somehow
                                }
                            }
                        , request);

person Olter    schedule 20.05.2013    source источник
comment
Вы действительно видели, как он загружает контейнер, когда вы используете POST, или это предположение?   -  person Anthony Russell    schedule 20.05.2013
comment
Обновленный вопрос, проблема явно не в методе GET. Найден способ получить значение jsessionid, но все еще не удается заставить приложение работать в одном сеансе. Есть предположения?   -  person Olter    schedule 30.05.2013


Ответы (1)


Итак, если значение jsessionid может быть получено указанным способом, решением будет использование HttpWebRequest, поскольку ExtendedWebClient каким-то образом игнорирует значение jsession.

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "GET";
            request.CookieContainer = new CookieContainer();
            request.CookieContainer.Add(new Uri(url, UriKind.Absolute), StoredCookieCollection._CookieCollection);
            request.BeginGetResponse(new AsyncCallback(GetSomething), request);

           private void GetSomething(IAsyncResult asynchronousResult)
           {
              // do something
           }

           // where in url a jsession value is added to the request as &jsessionid=value

Другая вещь, которая также не работает в Windows Phone, заключается в том, что вы не можете так легко сериализовать значение типа CookieCollection. Итак, я решил сохранить вместо него значение JSESSIONID типа String в настройках IsolatedStorage и создать статический класс StoredCookieCollection, который будет хранить CookieCollection во время работы приложения.

Итак, когда вы получаете значение jsessionid, оно сохраняется в настройках как строка и сохраняется в статическом классе как CookieCollection:

using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult))
                                    {
                                        CookieCollection cookies = response.Cookies;
                                        StoredCookieCollection._CookieCollection = cookies;
                                        ...
                                    }

Такой подход действительно заставит приложение работать за один сеанс.

Возможно, есть более элегантное решение с сериализацией CookieCollection, но я не нашел его.

person Olter    schedule 21.05.2013