1

我们的 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 中的错误。不应出现命名空间“ http://schemas.microsoft.com/2003/10/Serialization/Arrays ”中的“元素”“m_serializationArray” 。期待元素'm_keyRehashCount'。'。有关更多详细信息,请参阅 InnerException。

最内在的例外是

第 1 行位置 11619 中的错误。不应出现命名空间“ http://schemas.microsoft.com/2003/10/Serialization/Arrays ”中的“元素”“m_serializationArray” 。期待元素“m_keyRehashCount”。

我在 stackoverflow 或谷歌上找不到任何关于此的信息,我已经在 CSLA 论坛上发布了同样的问题,也许我也应该在 Connect 上发布它。但也许我在这里很幸运?

在将 .NET Framework 更新到 4.5.1 之前,我需要一些时间来备份我的开发环境

我可以想到两种可能的解决方案:

  • 将 2008 服务器升级到 .NET 4.5.1。
  • 强制客户端软件使用 .NET 4.5

是否可以强制客户端软件仅使用 .NET 4.5?还有什么想法吗?

4

2 回答 2

3

我可以从头到尾重现这个问题。在此期间,我想提供一些事实,看看这是否对您有所帮助。

根据文档, NetDataContractSerializer比 DataContractSerializer 更具限制性。

NetDataContractSerializer 在一个重要方面与 DataContractSerializer 不同:NetDataContractSerializer 在序列化的 XML 中包含 CLR 类型信息,而 DataContractSerializer 不包含。因此,只有在序列化和反序列化端共享相同的 CLR 类型时,才能使用 NetDataContractSerializer。

我相信 4.5.1 中的 ConcurrentDictionary 类型添加了一个名为 m_keyRehashCount 的属性或成员变量,这在 4.5 版本的 ConcurrentDictionary 中是找不到的。尝试在 4.5.1 机器上反序列化此对象时 - 序列化程序期望此缺少的属性导致此异常。

  <m_keyRehashCount>0</m_keyRehashCount>

以下是解决此问题的几种方法:

  1. 将您的服务器机器也升级到 4.5.1。.net 4.5.1 是对 .net 4.5 的免费升级,它还修复了 .net 4.5 中发现的一些兼容性问题。

  2. 使用 DataContractSerializer 而不是 NetDataContractSerializer,因为这不希望在序列化和反序列化端使用完全相同的 CLR 类型。

  3. 更改为使用 Dictionary 而不是 ConcurrentDictionary 因为我看到这种类型工作正常。
于 2013-10-30T14:58:11.800 回答
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;
    }
}
于 2014-02-11T09:07:03.327 回答