.NET 4.5.1 WCF序列化异常

时间:2013-10-25 09:15:57

标签: wcf .net-4.5 csla

我们的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之前,我需要一些时间备份我的开发环境

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

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

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

2 个答案:

答案 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>

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

  1. 将服务器计算机升级到4.5.1。 .net 4.5.1是对.net 4.5的免费升级,它也修复了.net 4.5中的一些compat问题。

  2. 使用DataContractSerializer代替NetDataContractSerializer 不希望序列化和完全相同的CLR类型 反序列化结束。

  3. 更改为使用词典 我看到这种类型的ConcurrentDictionary工作 细。

答案 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;
    }
}