質問

Our LOB application is a client server application which uses CSLA business objects, those business objects are being serialized using the NetDataContractSerializer. The server side is running on WCF and the client has endpoints.

This all works when the client software is running from Windows 7 or Windows 8 having .NET 4.5 installed.

When running the client software on Windows 8 or Windows 8.1 with the latest .NET 4.5.1 Framework the following exception occurs.

The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://ws.lhotka.net/WcfDataPortal:FetchResult. The InnerException message was 'Error in line 1 position 11619. 'Element' 'm_serializationArray' from namespace 'http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Expecting element 'm_keyRehashCount'.'. Please see InnerException for more details.

The most inner exception is

Error in line 1 position 11619. 'Element' 'm_serializationArray' from namespace 'http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Expecting element 'm_keyRehashCount'.

I cannot find anything about this on stackoverflow or on google, i have posted this same question on the CSLA forums and perhaps i should also post it on Connect. But maybe i'm lucky here?

I need some time to backup my development environment before i update the .NET Framework to 4.5.1

I can think of two possible solutions:

  • upgrade the 2008 server to .NET 4.5.1.
  • force the client software to use .NET 4.5

Is it possible to force the client software to use .NET 4.5 only? Any other idea's?

役に立ちましたか?

解決

I can reproduce this issue from my end. I would like to give a few facts to see if this would help you in the meantime.

NetDataContractSerializer is more restrictive than a DataContractSerializer as per the documentation.

The NetDataContractSerializer differs from the DataContractSerializer in one important way: the NetDataContractSerializer includes CLR type information in the serialized XML, whereas the DataContractSerializer does not. Therefore, the NetDataContractSerializer can be used only if both the serializing and deserializing ends share the same CLR types.

I believe the type ConcurrentDictionary in 4.5.1 has added a property or member variable named m_keyRehashCount which is not found in the 4.5 version of the ConcurrentDictionary. While trying to de-serialize this object on a 4.5.1 machine – the serializer expects this missing property resulting in this exception.

  <m_keyRehashCount>0</m_keyRehashCount>

Here are a few ways to solve this problem:

  1. Upgrade your server machine as well to 4.5.1. .net 4.5.1 is a free upgrade to .net 4.5 which also has fixes for some compat issues found in .net 4.5.

  2. Use DataContractSerializer instead of NetDataContractSerializer as this does not expect the exact same CLR types at both serializing and deserializing ends.

  3. Change to use Dictionary instead of a ConcurrentDictionary as I see this type works fine.

他のヒント

If you have previously serialized objects (serialized with pre 4.5.1) which contain ConcurrentDictionary you can deserialize it in 4.5.1 using the following example.

This example only help deserializing already serialized ConcurrentDictionary objects by creating new class which can deserialize using the ConcurrentDictionary serialization XML, see also other answers.

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;
    }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top