5

I have a production app that makes two calls via HttpWebRequest. The first call sets a session and receives cookies back to maintain the session, the second call is for data from the api. The responses are httponly. I am using a shared CookieContainer between the two calls, but the second call always fails. I narrowed the problem down to the cookies not being sent in the second request. I've used Network Monitor to watch the traffic, and if I explicitly set the cookies in the second request (see code below), the call succeeds. Anybody have any ideas on this issue? I need to figure out how to get it to work with the shared CookieContainer.

private string URL_01 = "https:// [...]";
private string URL_02 = "https:// [...]";
private CookieContainer _cookieContainer = new CookieContainer();
private NetworkCredential nc = new NetworkCredential("username", "password");

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
HttpWebRequest request = HttpWebRequest.CreateHttp(URL_01);
request.CookieContainer = _cookieContainer;
request.Credentials = nc;
request.UseDefaultCredentials = false;
request.BeginGetResponse(new AsyncCallback(HandleResponse), request);
}

public void HandleResponse(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;

if (request != null)
{
    using (WebResponse response = request.EndGetResponse(result))
    {
         using (StreamReader reader = new StreamReader(response.GetResponseStream()))
         {
             string data = reader.ReadToEnd();

             // gets returned data and deserializes it to an object
             SessionObject so = JsonConvert.DeserializeObject<SessionObject>(data);

             if (so.DeviceAPI.Session == "true")
             {
                // make a second call for the data
                HttpWebRequest requestData = HttpWebRequest.CreateHttp(URL_02);

                // when this is used, the call fails
                requestData.CookieContainer = _cookieContainer;

                // when this is used, the call works
                //requestData.Headers[HttpRequestHeader.Cookie] = "_key=value; _secret=value";

                requestData.Credentials = nc; 
                requestData.BeginGetResponse(new AsyncCallback(DataResponse), requestSongData);
                    }
                }
            }
        }
    }

    public void DataResponse(IAsyncResult DataResult)
    {
        HttpWebRequest requestData = DataResult.AsyncState as HttpWebRequest;

        if (requestData != null)
        {

            using (WebResponse dataResponse = requestData.EndGetResponse(DataResult))
            {
                using (StreamReader reader = new StreamReader(dataResponse.GetResponseStream()))
                {
                    string data = reader.ReadToEnd();
                    // do something with the data
                }
            }
        }
    }
}

}

Jeff Paries
  • 81
  • 1
  • 5

2 Answers2

3

This problem is a known issue with the CookieContainer when the domain name has no "www" on it. The CookieContainer is expecting a "www" and does not identify existing cookies for the domain.

The work around was to read the cookies from the response headers and add them to any other requests.

Was considered for a fix for Mango, but got pushed out.

Jeff

Jeff Paries
  • 81
  • 1
  • 5
0

I had his issue and it seemed to be with using an old cookie container. Just create a new one by Iterating through the old one, and creating new cookies.

Step 1. Create a dictionary to store cookies.

//create a dictionary to store your persistent cookies
public static Dictionary<string, Cookie> CookieCollection { get; set; }

Step 2. Add the cookies you have stored, onto the webrequest before it's sent off.

var request = WebRequest.Create(...);

//add the cookies you have in your persistent cookie jar

foreach (KeyValuePair<string, Cookie> cookie in _collection)
            {
                try
                {
                    request.CookieContainer.Add(request.RequestUri, new Cookie(cookie.Value.Name, cookie.Value.Value));
                }
                catch
                {
                }
            }

Step 3. Saving the Cookies

ResponseCallback(...) {

//update your local cookie list as required
   foreach (Cookie clientcookie in response.Cookies)
            {
                if (!_collection.ContainsKey(clientcookie.Name))
                    _collection.Add(clientcookie.Name, clientcookie);
                else
                    _collection[clientcookie.Name] = clientcookie;
            }
}
William Melani
  • 4,270
  • 1
  • 21
  • 44
  • When I try this code, I get an error that says "foreach statement cannot operate on variables of type 'System.Net.CookieContainer' because 'System.Net.CookieContainer' does not contain a public definition for 'GetEnumerator'. Is this the way you were able to utilize it? Thanks. – Jeff Paries Sep 29 '11 at 16:38
  • @JeffParies Sorry about that, was away from computer and couldn't verify in code. I've updated the answer. – William Melani Sep 29 '11 at 17:36
  • thanks, I will see if I can implement this... does it work on httponly cookies? – Jeff Paries Sep 29 '11 at 17:53
  • No. Cookies marked with HttpOnly cannot be saved. See http://forums.create.msdn.com/forums/p/64708/396364.aspx#396364 – William Melani Sep 29 '11 at 18:00
  • These cookies are HttpOnly - I don't necessarily need to save them, but they are not persisting between calls. – Jeff Paries Sep 29 '11 at 18:02
  • @JeffParies yeah sorry that's what I meant by saved. WP7 does not let you reuse the cookie. Had to convince a client to change their webservices b/c of this issue personally. – William Melani Sep 29 '11 at 18:08
  • My understanding is that the CookieContainer is there to persist the cookies between requests, and even though you can't "see" the httponly ones, they are carried over as well. Only, it's not working. – Jeff Paries Sep 29 '11 at 20:04
  • willmel - Is this code WP7? Doesn't seem to work for me (no response.Cookies, can't foreach a cookiecollection, etc.). – Jeff Paries Sep 30 '11 at 04:18