我们的LOB应用程序是一个使用CSLA业务对象的客户端服务器应用程序,这些业务对象正在使用NetDataContractSerializer进行序列化。服务器端在WCF上运行,客户端有端点。
当客户端软件从安装了.NET 4.5的Windows 7或Windows 8运行时,这一切都有效。
在使用最新.NET 4.5.1 Framework的Windows 8或Windows 8.1上运行客户端软件时,会发生以下异常。
格式化程序在尝试反序列化时抛出异常 消息:尝试反序列化参数时出错 http://ws.lhotka.net/WcfDataPortal:FetchResult。 InnerException 消息是'第1行位置错误11619.'元素' 来自命名空间的'm_serializationArray' 'http://schemas.microsoft.com/2003/10/Serialization/Arrays'不是 预期。期待元素'm_keyRehashCount'。'。请参阅 InnerException以获取更多详细信息。
最内在的例外是
第1行位置错误11619.'元素''m_serializationArray'来自 名称空间'http://schemas.microsoft.com/2003/10/Serialization/Arrays' 不是预期的。期待元素'm_keyRehashCount'。
我在stackoverflow或google上找不到任何相关内容,我在CSLA论坛上发布了同样的问题,也许我也应该在Connect上发布。但也许我很幸运?
在将.NET Framework更新到4.5.1之前,我需要一些时间备份我的开发环境
我可以想到两种可能的解决方案:
是否可以强制客户端软件仅使用.NET 4.5? 还有其他想法吗?
答案 0 :(得分:3)
我可以从我的角度重现这个问题。我想提供一些事实,看看这是否会在此期间帮助你。
根据文档,NetDataContractSerializer比DataContractSerializer更具限制性。
NetDataContractSerializer与DataContractSerializer的不同之处在于一个重要方面:NetDataContractSerializer在序列化XML中包含CLR类型信息,而DataContractSerializer则不包含。因此,仅当序列化和反序列化结束共享相同的CLR类型时,才能使用NetDataContractSerializer。
我相信4.5.1中的ConcurrentDictionary类型添加了一个名为m_keyRehashCount的属性或成员变量,该变量在ConcurrentDictionary的4.5版本中找不到。尝试在4.5.1计算机上反序列化此对象时 - 序列化程序期望此缺少的属性导致此异常。
<m_keyRehashCount>0</m_keyRehashCount>
以下是解决此问题的几种方法:
将服务器计算机升级到4.5.1。 .net 4.5.1是对.net 4.5的免费升级,它也修复了.net 4.5中的一些compat问题。
使用DataContractSerializer代替NetDataContractSerializer 不希望序列化和完全相同的CLR类型 反序列化结束。
答案 1 :(得分:1)
如果您之前已经序列化了包含ConcurrentDictionary的对象(使用4.5.1之前的序列化),则可以使用以下示例在4.5.1中对其进行反序列化。
此示例仅通过创建可以使用ConcurrentDictionary序列化XML反序列化的新类来帮助反序列化已经序列化的ConcurrentDictionary对象,另请参阅其他答案。
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using ClassLibrary1.Model;
namespace SerializaerDesrializer
{
[DataContract]
public class CompositeDictionaryHolder
{
// Old serialized data member:
//[DataMember]
//private MyConcurrentDictionary<int, string> _concuurentDictionary = new MyConcurrentDictionary<int, string>();
private ConcurrentDictionary<int, string> _concuurentDictionaryInternal = new ConcurrentDictionary<int, string>();
[DataMember]
private InternalArray _concuurentDictionary;
public CompositeDictionaryHolder()
{
// Just an example:
_concuurentDictionaryInternal.TryAdd(1, "1");
_concuurentDictionaryInternal.TryAdd(2, "2");
_concuurentDictionaryInternal.TryAdd(3, "3");
}
/// <summary>
/// Get the data array to be serialized
/// </summary>
[OnSerializing]
private void OnSerializing(StreamingContext context)
{
// save the data into the serialization array to be saved
_concuurentDictionary = new InternalArray(_concuurentDictionaryInternal.ToArray());
}
/// <summary>
/// Construct the dictionary from a previously seiralized one
/// </summary>
[OnDeserialized]
private void OnDeserialized(StreamingContext context)
{
_concuurentDictionaryInternal = new ConcurrentDictionary<int, string>(_concuurentDictionary.m_serializationArray);
}
}
[DataContract(
Namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")]
public class InternalArray
{
public InternalArray()
{
}
public InternalArray(KeyValuePair<int, string>[] serializationArray)
{
m_serializationArrayInternal = serializationArray;
}
[DataMember]
public KeyValuePair<int, string>[] m_serializationArray
{
get { return m_serializationArrayInternal; }
set { m_serializationArrayInternal = value; }
}
private KeyValuePair<int, string>[] m_serializationArrayInternal;
}
}