2011-09-27 67 views
4

更新1:經過更多的研究,我不確定這是可能的,I created a UserVoice entry on fixing itWindows Phone 7芒果保存CookieContainer的狀態

我試圖在應用程序退出時保存CookieContainer,或發生墓碑事件時發生,但我遇到了一些問題。

I've tried to save CookieContainer in the AppSettings but when loaded, the cookies are gone

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

在做了更多的研究之後,看起來周圍的工作就是從容器中獲取cookie並以另一種方式保存它們。這工作得很好,直到我打另一個障礙。我無法使用.mydomain.com的URI訪問GetCookies。我相信這是因爲this bug。我可以在域表中看到cookie,.mydomain.com,但GetCookies無法在該特定的cookie上工作。

The bug is posted again here

還擁有讓餅乾從容器的問題太多 時域始於:

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

我發現了一個變通方法,使用反射遍歷domaintable並刪除'。'字首。

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]; 
     } 
    } 
} 

只有當調用InvokeMember時,纔會在SL中拋出MethodAccessException。這並不能真正解決我的問題,因爲我需要保留的cookie之一是HttpOnly,這是CookieContainer的原因之一。

如果服務器發送中HTTPOnly Cookie,您應該請求創建一個 System.Net.CookieContainer舉行餅乾, 雖然你不會看到或能夠訪問存儲在 餅乾容器。

那麼,有什麼想法?我錯過了一些簡單的東西嗎是否有另一種方法來保存CookieContainer的狀態,還是需要保存用戶信息(包括密碼),並在每次應用程序啓動時以及從墓碑中恢復時重新驗證它們?

回答

0

即使使用Reflection,您也無法訪問WP7以外的私有成員。這是一種安全措施,確保您無法調用內部系統API。

看起來你可能不走運。

+0

是的,你會認爲這將是一件簡單的事情。 –

+0

運氣不錯是正確的。 –

2

我寫了一個專門解決這個問題的CookieSerializer。序列化程序粘貼在下面。對於工作項目和方案,請訪問該項目的CodePlex 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>'s <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's 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); 
    } 
} 
+0

這是否適用於wp7?我不認爲wp7支持HTTPOnly cookie。 –

+0

HTTPOnly cookies將會出現,但即使您無法從代碼中讀取它也會被隱藏。你可以做什麼:你可以一次又一次地重新分配相同的CookieContainer與下一個隨後的所有請求。 – Somnath