【问题标题】:How to debug serialization error in tombstoned WP7 app如何在墓碑化的 WP7 应用程序中调试序列化错误
【发布时间】:2010-10-20 07:35:49
【问题描述】:

我在 OnNavigatedFrom 和 To 事件中处理我的 WP7 应用程序的当前状态,以便如果应用程序被墓碑化或者它们导航到不同的页面,它会将状态保存到内置的 PhoneApplicationService 状态。

我有一个简单的ViewModel which I dump to the state 让生活更轻松。当导航到我的应用程序中的不同页面时,状态存储良好并恢复正常(即我假设它此时正在序列化)。但是,当我 tombstone 应用程序(即开始按钮)时,我收到一个未处理的序列化错误,并且堆栈跟踪没有给我任何关于它失败原因的线索。

我尝试将实际调用包装在 try catch 块中以尝试查看问题所在,但这无济于事 - 这是运行时对我的对象进行墓碑处理时所做的事情与仅在页面之间存储它时所做的不同.

这是我的代码:

protected override void OnNavigatedFrom(NavigationEventArgs args)
{
   appService.State["TournamentViewModel"] = tournamentViewModel;
   base.OnNavigatedFrom(args);
}

protected override void OnNavigatedTo(NavigationEventArgs args)
{
    if (appService.State.ContainsKey("TournamentViewModel"))
    {
        tournamentViewModel = (TournamentViewModel)appService.State["TournamentViewModel"];
    }
    base.OnNavigatedTo(args);
}

这是生成的错误 - 我真的不知道问题出在哪里 - 我怎样才能更好地调试它?

异常信息: 消息:“安全异常” InnerException:“无法评估表达式”

堆栈跟踪:

   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateGetOnlyCollectionDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetGetOnlyCollectionDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.GetGetOnlyCollectionDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.XmlObjectSerializerContext.GetDataContractSkipValidation(Int32 typeId, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerializeReference(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
   at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
   at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at System.Runtime.Serialization.XmlFormatWriter.InternalSerialize(MethodInfo methodInfo, Object memberValue, Type memberType, Boolean writeXsiType, XmlObjectSerializerWriteContext context, XmlWriterDelegator xmlWriter)
   at System.Runtime.Serialization.XmlFormatWriter.WriteValue(Type memberType, Object memberValue, Boolean writeXsiType, XmlObjectSerializerWriteContext context, XmlWriterDelegator xmlWriter)
   at System.Runtime.Serialization.XmlFormatWriter.WriteMember(SerializingObject serObj, Int32 memberIndex, ClassDataContract derivedMostClassContract)
   at System.Runtime.Serialization.XmlFormatWriter.WriteClass(CallStackElement`1 callStackElement)
   at System.Runtime.Serialization.XmlFormatWriter.Serialize(XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlFormatWriter.InitializeCallStack(XmlWriterDelegator xmlWriterDel, Object obj, XmlObjectSerializerWriteContext writeContext, DataContract contract)
   at System.Runtime.Serialization.CollectionDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(Stream stream, Object graph)
   at Microsoft.Phone.Shell.StreamPersister.Serialize(IDictionary`2 dictionary, IEnumerable`1 knownTypes)
   at Microsoft.Phone.Shell.StreamPersister.Save(ShellPageManager shellPageManager, String key, IDictionary`2 dictionary, IEnumerable`1 knownTypes)
   at Microsoft.Phone.Shell.PhoneApplicationService.FireDeactivated()
   at Microsoft.Phone.Execution.NativeEmInterop.FireOnPause()

更新:通过反复试验,我发现问题出在 AppBar,它似乎不可序列化。我用 [IgnoreDataMember] 对其进行了标记,现在它在different problem 上抛出了一个更有意义的错误。我仍然想知道是否有任何简单的方法可以获取此信息...

【问题讨论】:

  • 如果没有一个可行的例子,很难说墓碑与标准导航有什么不同。对象可能处于不同状态的原因有很多,这会影响正确序列化的能力。

标签: serialization silverlight-3.0 windows-phone-7


【解决方案1】:

罗德尼,

我的理解是,当您将对象放入两个状态字典之一(PhoneApplicationPage 的一个和 PhoneApplicationServices 的另一个)中时,它不会立即序列化或反序列化。

如果您使用 Page.State 来存储数据,它会在您离开页面时序列化您的状态包,并在您返回页面时反序列化(而不是在您添加或读取状态包中的对象时)。

如果您使用 PhoneApplicationService.State,序列化会在您墓碑时发生,而反序列化会在应用程序重新激活时发生(尽管我不确定这是否与 PhoneApplicationService.Activated 事件相关联)。

顺便说一下,Page.State 不允许在页面之间共享数据。保存到 PhoneApplicationService.State 确实允许您这样做。

IsolatedStorage.AppSettings 似乎默默地处理反序列化问题,所以我不确定什么时候会发生。但是,当您调用 Save() 时会发生序列化。

詹姆斯

【讨论】:

    【解决方案2】:

    那么,您的 ViewModel 如何表达它的可序列化方式?就我个人而言,我倾向于避免可能复杂的序列化:一个相当简单的选择是让您的 ViewModel 能够显式地将自身转换为 XML 或从 XML 转换,然后自己手动执行该步骤,保存 XDocument(或其字符串表示)在应用程序状态。这样就很容易调试序列化步骤,查看生成的确切 XML 等。

    当然,这里使用 XML 是偶然的 - 如果您可以轻松地将所有内容放在 CSV 字符串中,那也很好。您可以在进入应用程序状态之前根据序列化表单轻松检查的任何内容。

    我意识到这回避了“自动”序列化的一些所谓的好处,但我遇到了很多难以诊断的任意对象自动序列化问题,我认为这些好处并没有超过缺点。

    【讨论】:

    • 谢谢乔恩,目前我并没有对它做任何花哨的事情 - 我很困惑的是它在离开页面时的工作方式,而不是在被墓碑化时 - 这不是证明类是可序列化的?它必须在停用时做一些不同的事情。堆栈跟踪对您有什么意义吗?我没有高兴地用谷歌搜索了它的几个不同部分——我真的不知道从哪里开始寻找。也许另一个问题是 - 我如何从这个自动序列化中排除部分类?也许我可以尝试通过消除过程找到它。
    • 您可以发布您的 TournamentViewModel 类定义吗?
    • 谢谢,我发现了错误 - 我正在使用 MVVM 技术在 VM 中创建 ApplicationBar 然后绑定到它(因为您无法在视图中绑定到 AppBar)。这导致了问题(我通过消除过程发现)所以我用 [IgnoreDataMember] 标记它并且它通过了这个问题。我的下一个问题是 VM 继承自没有公共无参数构造函数的 MVVMLight ViewModelBase,因此序列化失败! stackoverflow.com/questions/3976170/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    相关资源
    最近更新 更多