【问题标题】:WP7 IsolatedStorage XML file empty after app update应用程序更新后 WP7 隔离存储 XML 文件为空
【发布时间】:2012-04-04 20:23:28
【问题描述】:

我为我的 WP7 应用提交了更新,但我有用户抱怨他们的数据在更新后被删除了。我通过将 ViewModel 类序列化为 IsolatedStorage 中的 XML 文件来存储数据。在我的测试过程中,我注意到更新应用程序导致设置文件被我的 ViewModel 对象的新实例(具有默认值)的序列化副本部分覆盖。我以为我在写入 XML 文件时使用 FileMode.Create 解决了这个问题,但我猜不是。

会不会因为我向 ViewModel 对象添加了新属性并且从现有 XML 文件反序列化失败而导致序列化出错?如果无法从 XML 文件中读取一个新的 ViewModel 对象,我确实将我的代码设置为实例化一个新的 ViewModel 对象。如果是这种情况,是否意味着我无法向 ViewModel 对象添加任何新属性?

编辑:
这是我的 ViewModel 的结构,并不是那么复杂:

public class MyClass: INotifyPropertyChanged
{
    public MyClass()
    {
        // Set defaults
        this.Items= new ObservableCollection<Item>();
        this.TextTemplate = "default";
        this.HasSeenSomething = false;
    }

    public ObservableCollection<Item> Items { get; set; }
    // New properties added in app update
    public string TextTemplate { get; set; }
    public bool HasSeenSomething { get; set; }
}

这是我用来序列化/反序列化我的 ViewModel 的代码。我认为这是很标准的,但也许我搞砸了:

public static void WriteToXml<T>(T data, string path)
{
    var xmlWriterSettings = new XmlWriterSettings { Indent = true };
    using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
    {
        using (var stream = myIsolatedStorage.OpenFile(path, FileMode.Create))
        {
            var serializer = new XmlSerializer(typeof(T));
            using (var xmlWriter = XmlWriter.Create(stream, xmlWriterSettings))
            {
                serializer.Serialize(xmlWriter, data);
            }
        }
    }
}

public static T ReadFromXml<T>(string path)
{
    T data = default(T);
    try
    {
        using (var myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (myIsolatedStorage.FileExists(path))
            {
                using (var stream = myIsolatedStorage.OpenFile(path, FileMode.Open))
                {
                    try
                    {
                        var serializer = new XmlSerializer(typeof(T));
                        object instance = serializer.Deserialize(stream);
                        if (instance != null) data = (T)instance;
                    }
                    catch (System.Exception ex)
                    {
                        var e = ex;
                    }
                }
            }
        }
    }
    catch(System.Exception ex) 
    {
        var e = ex;
    }
    return data;
}

【问题讨论】:

    标签: windows-phone-7 xml-serialization windows-phone-7.1 isolatedstorage


    【解决方案1】:

    可以,但有一些问题。

    1. 您需要确保不会以在反序列化时会中断的方式更改属性。因此,将 Int 更改为 String 是可以的(尽管我不建议这样做),但相反的情况可能会中断。
    2. 您需要记住,反序列化对象时不会调用 ctor。这意味着如果你在 ctor 中执行以下操作:

      公共 MyClass() { MyV2Collection = new Collection(); }

    如果集合为空,您没有其他机制可以新建集合,您将在第一次尝试访问该属性时死于 NullRef。

    一毛钱兑美元,我敢打赌你正在达到 pt #2。

    修复它相当容易,但你需要记住去做。选项有:

    1. 在属性访问器中,检查支持字段是否为空,如果是则实例化它。
    2. 创建一个带有[OnDeserialized] 属性的函数(public)。该代码将在反序列化完成后运行,您可以在那里实例化您的成员。

    【讨论】:

    • 我认为空集合不是问题。该集合中将包含数据,否则用户将不会丢失任何东西。我添加的新属性是字符串和布尔值,没有什么可以阻止模型反序列化。
    • 明白了。最好的办法就是测试它——在模拟器上安装旧二进制文件,运行它等,使用独立存储工具获取文件,安装新二进制文件,将旧文件放在独立存储中并调试它。 wptools.codeplex.com
    • 部署(通过安装)我的 v1.0 xap 到我的设备并保存一些项目后,我部署了 v1.1(通过更新)并且数据完好无损(新属性设置为默认值)。我每次都用不同的数据尝试了几次,但我无法让数据损坏。我设法获得损坏的唯一方法是从 v1.1 更新到 v1.0。这完全有道理,因为属性不会对齐。我不知道投诉的客户会发生什么。
    • 数据可以有多大?我的应用程序采用“备份和保存”机制,以确保我不会在保存期间崩溃或应用程序强制关闭时意外丢失数据。你可能想做类似的事情。
    • 即使他们有相当多的项目集合,数据的大小也不会那么大,因为它大多只是整数。我认为在保存之前添加备份副本是个好主意,我将在我的应用程序中实现它。感谢您的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多