none
DataContractJsonSerializer and underlying environments RRS feed

  • General discussion

  • Hello,

    I am starting a new discussion because I ran into a weird issue with the DataContractJsonSerializer.
    Indeed, we used this serializer on a project targeting framework 4 where we serialized an IOrderedEnumerable. I can reproduce this issue with the following code:

    class Program
        {
            public class Foo
            {
                public string StringProperty { get; set; }
    
                public int IntProperty { get; set; }
    
                public Foo(string strProp, int intProp)
                {
                    StringProperty = strProp;
                    IntProperty = intProp;
                }
            }
    
            static void Main(string[] args)
            {
                MemoryStream ms = new MemoryStream();
                DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Foo>));
    
                List<Foo> inputList = new List<Foo>()
                {
                    new Foo("test1", 1), 
                    new Foo("test2", 2)
                };
    
                serializer.WriteObject(ms, new List<Foo>() { }.OrderBy(x => x.IntProperty));
    
                string result = Encoding.UTF8.GetString(ms.ToArray());
            }
        }

    This program compiles without any fuss but at runtime, the behavior is different according the operating system you run the program upon. Indeed, there is no issue on a Windows 8 system (same result on an IIS server hosted on a Windows Server 2012). However, if you run this sample program on a Windows XP system for instance (same result on an IIS server hosted on a Windows Server 2010), you get an InvalidDataContractException saying that IOrderedEnumerable is not serializable (which is true actually according to the documentation):

    Unhandled Exception: System.Runtime.Serialization.InvalidDataContractException:
    Type 'System.Linq.OrderedEnumerable`2[ConsoleApplication1.Class1,System.Int32]'
    cannot be serialized. Consider marking it with the DataContractAttribute attribu
    te, and marking all of its members you want serialized with the DataMemberAttrib
    ute attribute.  If the type is a collection, consider marking it with the Collec
    tionDataContractAttribute.  See the Microsoft .NET Framework documentation for o
    ther supported types.
       at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.Throw
    InvalidDataContractException(String message, Type type)
       at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.Creat
    eDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDa
    taContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
       at System.Runtime.Serialization.DataContractSerializer.GetDataContract(DataCo
    ntract declaredTypeContract, Type declaredType, Type objectType)
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWrite
    ObjectContent(XmlWriterDelegator writer, Object graph)
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.InternalWrite
    Object(XmlWriterDelegator writer, Object graph)
       at System.Runtime.Serialization.XmlObjectSerializer.InternalWriteObject(XmlWr
    iterDelegator writer, Object graph, DataContractResolver dataContractResolver)
       at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptio
    ns(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractRes
    olver)
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(X
    mlDictionaryWriter writer, Object graph)
       at System.Runtime.Serialization.Json.DataContractJsonSerializer.WriteObject(S
    tream stream, Object graph)
       at ConsoleApplication1.Program.Main(String[] args) in c:\users\christophe\doc
    uments\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication1\Progr
    am.cs:line 17

    I know that IOrderedEnumerable is not supposed to be serializable but I was pretty sure that the aim of having the CLR between the operating system and the applications made the underlying operating system "irrelevant" and had the upside of providing the same behaviors on all OS running the CLR. Was I wrong ? Am I missing something here ? Does someone have an explanation ?

    Thanks for your replies.

    Saturday, November 30, 2013 10:19 AM

All replies

  • "I was pretty sure that the aim of having the CLR between the operating system and the applications made the underlying operating system "irrelevant" and had the upside of providing the same behaviors on all OS running the CLR. Was I wrong ?"

    This has nothing to do with the OS, it has to do with the .NET Framework version. On XP you're running .NET 4.0 since that's the latest version of .NET that still supports XP.

    Win8/2012 come with .NET 4.5 preinstalled

    Saturday, November 30, 2013 10:45 AM
    Moderator
  • Even if my project explicitly targets .NET 4 ?

    I'm gonna try on a Win7 machine just to make sure. I will keep you posted.


    Saturday, November 30, 2013 11:14 AM
  • OK. So, on a machine running Win7 with the .NET 4.5 framework, it works fine. So you're right Mike Danes. So there is another question :) Did IOrderedEnumerable become serializable through the DataContractJsonSerializer on .NET 4.5 ? Because I'm still looking for an explanation :)

    Besides, it also means that this will be an actual issue for applications we will migrate to Server 2012... Shouldn't there be any breaking changes between two versions ?
    Saturday, November 30, 2013 11:28 AM
  • "Did IOrderedEnumerable become serializable through the DataContractJsonSerializer on .NET 4.5 ?"

    Not really. IOrderedEnumerable is supposed to be serializable anyway because it inherits IEnumerable. The issue here seems to be that you have created the serializer with the wrong type, you used List<Foo> but you call write with an OrderedEnumerable<T> object produced by LINQ. As far as I can tell your code works fine on XP/.NET4 is you create the serializer with the correct type, IEnumerable<Foo>.

    I don't know why this apparently incorrect use of DataContractJsonSerializer works in 4.5 but not in 4.0 but it probably doesn't really matter since it's "incorrect use".

    "Besides, it also means that this will be an actual issue for applications we will migrate to Server 2012..."

    Well, there may be issues. Though this particular issue doesn't look like a problem to me. You have a piece of code that failed to work in 4.0 but works in 4.5, not quite a breaking change.

    "Shouldn't there be any breaking changes between two versions ?"

    Well, there shouldn't be breaking changes but after all it's a different version of .NET and a different version of OS. There's always a small chance that something got changed either accidentally or intentionally and that something breaks an application or exposes bugs in an application.

    Saturday, November 30, 2013 12:15 PM
    Moderator