简体   繁体   English

Windows Phone 7 Mango保存CookieContainer的状态

[英]Windows Phone 7 Mango saving the state of a CookieContainer

update1: After more research I'm not sure this is possible, I created a UserVoice entry on fixing it . 更新1:经过更多研究后,我不确定是否可行, 我在修复它时创建了一个UserVoice条目

I'm trying to save CookieContainer on app exit or when Tombstoning happens but I've run into some problems. 我正在尝试在应用程序出口或发生Tombstoning时保存CookieContainer,但遇到了一些问题。

I've tried to save CookieContainer in the AppSettings but when loaded, the cookies are gone . 我试图将CookieContainer保存在AppSettings中,但是加载后,cookies消失了

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

After doing more research it seemed like the work around was to grab the cookies from the container and save them another way. 经过更多研究后,似乎可以解决的方法是从容器中取出cookie并以其他方式保存它们。 That worked fine until I hit another snag. 直到我遇到另一个障碍之前,这种方法都很好。 I'm unable to GetCookies with a Uri of .mydomain.com. 我无法使用Uri为.mydomain.com的GetCookies。 I belive it's because of this bug . 我相信这是因为这个错误 I can see the cookie, .mydomain.com in the domaintable but GetCookies doesn't work on that particular cookie. 我可以在域表中看到cookie.mydomain.com,但GetCookies不适用于该特定cookie。

The bug is posted again here . 该错误再次发布在这里

There is also a problem with getting cookies out of a container too when the domain begins with a .: 当域以。开头时,从容器中取出cookie也是一个问题。

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 work around for that using reflection to iterate the domaintable and remove the '.' 我找到了解决方法,使用反射来迭代域表并删除“。”。 prefix. 字首。

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 InvokeMember is called a MethodAccessException is thrown in SL. 仅当调用InvokeMember时,才会在SL中引发MethodAccessException。 This doesn't really solve my problem as one of the cookies I need to preserve is HttpOnly, which is one of the reasons for the CookieContainer. 这并不能真正解决我的问题,因为我需要保留的Cookie之一是HttpOnly,这是CookieContainer的原因之一。

If the server sends HTTPOnly cookies, you should create a System.Net.CookieContainer on the request to hold the cookies, although you will not see or be able to access the cookies that are stored in the container. 如果服务器发送HTTPOnly cookie,尽管您将看不到或无法访问存储在容器中的cookie,但应在请求中创建一个System.Net.CookieContainer来保存cookie。

So, any ideas? 那么,有什么想法吗? Am I missing something simple? 我是否缺少简单的东西? Is there another way to save the state of the CookieContainer or do I need to save off the users info including password and re-authentic them every time the app starts and when coming back from tombstoning? 还有另一种方法来保存CookieContainer的状态,还是我需要保存用户信息(包括密码),并在每次应用启动时和从逻辑删除中回来时对它们进行重新身份验证?

I have written a CookieSerializer that specifically address this issue. 我写了一个CookieSerializer专门解决了这个问题。 The serializer is pasted below. 序列化器粘贴在下面。 For a working project and scenario, please visit the project's CodePlex site . 对于有效的项目和方案,请访问该项目的CodePlex网站

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

You cannot access private members outside of your assembly in WP7, even with Reflection. 即使使用反射,您也不能在WP7中访问程序集之外的私人成员。 It's a security measure put in place to ensure you cannot call internal system APIs. 这是一项安全措施,可确保您无法调用内部系统API。

It looks like you may be out of luck. 看来您可能不走运。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM