如何在WP7应用程序中调试序列化错误

3
我正在处理我的WP7应用程序的当前状态,在OnNavigatedFrom和To事件中,以便如果应用程序被挂起或导航到另一个页面,则将状态保存到内置的PhoneApplicationService状态。

我有一个简单的ViewModel,我将其转储到状态中,以使生活更轻松。在我的应用程序内导航到不同页面时,状态被很好地存储和恢复(即我认为它在此时进行序列化)。但是,当我挂起应用程序(即开始按钮)时,我会收到一个未处理的序列化错误,并且堆栈跟踪没有给我任何关于失败原因的线索。

我已经尝试将实际调用包装在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);
}

这是生成的错误 - 我真的无法弄清问题出在哪里 - 我该如何更好地调试?

异常信息: 消息:“SecurityException” 内部异常:“无法评估表达式”

堆栈跟踪:

   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]标记了它,现在它会在其他问题上抛出更有意义的错误。我仍然想知道是否有任何简单的方法来捕获这些信息...


很难说墓碑化与标准导航有什么不同,没有一个可行的示例。对象可能处于不同状态的各种原因会影响正确序列化的能力。 - Matt Lacey
2个回答

3

罗德尼,

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

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

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

顺便说一句,Page.State不允许在页面之间共享数据。将数据保存到PhoneApplicationService.State中可以实现此功能。

IsolatedStorage.AppSettings似乎会默默地处理反序列化问题,因此我不确定何时会发生反序列化。但是,序列化会在调用Save()时发生。

詹姆斯


2
您的 ViewModel 是如何表达其可序列化方式的呢?个人而言,我倾向于避免潜在的复杂序列化:一个相当简单的选项是赋予您的 ViewModel 显式地将自己转换为/从 XML 的能力,然后手动执行该步骤,将 XDocument (或其字符串表示形式)保存在应用程序状态中。这样做可以轻松调试序列化步骤,查看所生成的确切 XML 等。
当然,这里使用 XML 实际上是次要的 - 如果您可以很容易地把所有东西放到 CSV 字符串中,那也可以。任何您在将对象放入应用程序状态之前可以轻松检查其序列化形式的东西。
我意识到这样有些绕过了“自动”序列化的某些所谓好处,但我遇到过足够难以诊断的问题,涉及任意对象的自动序列化,我认为好处不大于缺点。

谢谢Jon,目前我没有对它做任何花哨的事情。我困惑的是当我离开页面但未被墓穴化时它的工作方式 - 这不是证明这个类是可序列化的吗?它在停用时必须做一些不同的事情。堆栈跟踪对您有任何意义吗?我已经用它的几个不同部分搜索过谷歌,但没有找到答案 - 我真的不知道从哪里开始查找。也许另一个问题是 - 如何从此自动序列化中排除类的某些部分?也许我可以通过逐个排除来尝试找到它。 - Rodney
你能否发表你的TournamentViewModel类定义? - indyfromoz
谢谢,我找到了错误 - 我在VM中使用MVVM技术创建ApplicationBar, 然后再对其进行数据绑定 (因为不能在视图中绑定AppBar)。这就导致了问题 (通过排除法找到),所以我用 [IgnoreDataMember] 进行标记,并解决了这个问题。我的下一个问题是,VM继承自MVVMLight ViewModelBase,但它没有公共的无参构造函数,因此序列化失败!https://dev59.com/UVHTa4cB1Zd3GeqPQEU4 - Rodney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接