Windows Phone 7 Mango Saves CookieContainer State

update1: After more research, I'm not sure if this is possible, I created a UserVoice entry to fix it .

I try to save a CookieContainer when I exit the application or when Tombstoning happens, but I ran into some problems.

I tried to save the CookieContainer in AppSettings, but the cookies disappeared on loading .

Researching this internally, DataContractSerializer cannot serialize cookies. This seems to be a behavior that Windows Phone inherited from Silverlight DataContractSerializer. 

After doing more research, it seemed like the work around was to grab the cookies from the container and store them in a different way. This worked fine until I hit another snag. I can not getcookies with Uri.mydomain.com. I believe in this because of this error . I can see the cookie, .mydomain.com in domaintable, but GetCookies does not work on this particular cookie.

The error is posted here again .

There is also a problem with getting cookies from the container when the domain starts with:

 CookieContainer container = new CookieContainer(); container.Add(new Cookie("x", "1", "/", ".blah.com")); CookieCollection cv = container.GetCookies(new Uri("http://blah.com")); cv = container.GetCookies(new Uri("http://w.blah.com")); 

I found a job for this, using reflection to iterate over the dominant and remove the ".". Console.

 private void BugFix_CookieDomain(CookieContainer cookieContainer) { System.Type _ContainerType = typeof(CookieContainer); var = _ContainerType.InvokeMember("m_domainTable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.Instance, null, cookieContainer, new object[] { }); ArrayList keys = new ArrayList(table.Keys); foreach (string keyObj in keys) { string key = (keyObj as string); if (key[0] == '.') { string newKey = key.Remove(0, 1); table[newKey] = table[keyObj]; } } } 

Only when an InvokeMember is thrown is a MethodAccessException is thrown in the SL. This really does not solve my problem since one of the cookies I need to save is HttpOnly, which is one of the reasons for CookieContainer.

If the server sends HTTPOnly cookies, you must create a System.Net.CookieContainer at the request of the cookie, although you will not see or be able to access the cookies stored in the container.

So, any ideas? Did I miss something? Is there any other way to keep the CookieContainer state or do I need to save information about users, including the password, and re-authenticate them each time the application starts and when it returns from the tombstone?

+4
source share
2 answers

You cannot access private members outside of your assembly in WP7, even with Reflection. This is a security measure designed to ensure that you cannot invoke internal system APIs.

Sounds like you might be out of luck.

0
source

I wrote a CookieSerializer that specifically solves this problem. The serializer is inserted below. For a working draft and script, please visit the CodePlex project site .

 public static class CookieSerializer { /// <summary> /// Serializes the cookie collection to the stream. /// </summary> /// <param name="cookies">You can obtain the collection through your <see cref="CookieAwareWebClient">WebClient</see> <code>CookieContainer.GetCookies(Uri)</code>-method.</param> /// <param name="address">The <see cref="Uri">Uri</see> that produced the cookies</param> /// <param name="stream">The stream to which to serialize</param> public static void Serialize(CookieCollection cookies, Uri address, Stream stream) { using (var writer = new StreamWriter(stream)) { for (var enumerator = cookies.GetEnumerator(); enumerator.MoveNext();) { var cookie = enumerator.Current as Cookie; if (cookie == null) continue; writer.WriteLine(address.AbsoluteUri); writer.WriteLine(cookie.Comment); writer.WriteLine(cookie.CommentUri == null ? null : cookie.CommentUri.AbsoluteUri); writer.WriteLine(cookie.Discard); writer.WriteLine(cookie.Domain); writer.WriteLine(cookie.Expired); writer.WriteLine(cookie.Expires); writer.WriteLine(cookie.HttpOnly); writer.WriteLine(cookie.Name); writer.WriteLine(cookie.Path); writer.WriteLine(cookie.Port); writer.WriteLine(cookie.Secure); writer.WriteLine(cookie.Value); writer.WriteLine(cookie.Version); } } } /// <summary> /// Deserializes <see cref="Cookie">Cookie</see>s from the <see cref="Stream">Stream</see>, /// filling the <see cref="CookieContainer">CookieContainer</see>. /// </summary> /// <param name="stream">Stream to read</param> /// <param name="container">Container to fill</param> public static void Deserialize(Stream stream, CookieContainer container) { using (var reader = new StreamReader(stream)) { while (!reader.EndOfStream) { var uri = Read(reader, absoluteUri => new Uri(absoluteUri, UriKind.Absolute)); var cookie = new Cookie(); cookie.Comment = Read(reader, comment => comment); cookie.CommentUri = Read(reader, absoluteUri => new Uri(absoluteUri, UriKind.Absolute)); cookie.Discard = Read(reader, bool.Parse); cookie.Domain = Read(reader, domain => domain); cookie.Expired = Read(reader, bool.Parse); cookie.Expires = Read(reader, DateTime.Parse); cookie.HttpOnly = Read(reader, bool.Parse); cookie.Name = Read(reader, name => name); cookie.Path = Read(reader, path => path); cookie.Port = Read(reader, port => port); cookie.Secure = Read(reader, bool.Parse); cookie.Value = Read(reader, value => value); cookie.Version = Read(reader, int.Parse); container.Add(uri, cookie); } } } /// <summary> /// Reads a value (line) from the serialized file, translating the string value into a specific type /// </summary> /// <typeparam name="T">Target type</typeparam> /// <param name="reader">Input stream</param> /// <param name="translator">Translation function - translate the read value into /// <typeparamref name="T"/> if the read value is not <code>null</code>. /// <remarks>If the target type is <see cref="Uri">Uri</see> , the value is considered <code>null</code> if it an empty string.</remarks> </param> /// <param name="defaultValue">The default value to return if the read value is <code>null</code>. /// <remarks>The translation function will not be called for null values.</remarks></param> /// <returns></returns> private static T Read<T>(TextReader reader, Func<string, T> translator, T defaultValue = default(T)) { var value = reader.ReadLine(); if (value == null) return defaultValue; if (typeof(T) == typeof(Uri) && String.IsNullOrEmpty(value)) return defaultValue; return translator(value); } } 
+2
source

All Articles