CustomConverter and Resolving To A Derived Type

Apr 23, 2010 at 3:11 PM
Edited Apr 23, 2010 at 3:21 PM

Based on the code sample below, I need to de-serialize a json string back into an instance of the ContainerClass type. Its ClassArray property is an array of BaseClass, but it actually contains instances of DerivedClass1 and DerivedClass2, which inherit from BaseClass. Here is the json string that I am trying to de-serialize:  

{ 

 "SomePropertyToSerialize": "Populated from unit test", 

 "ClassArray": [ 

 { 

 "DerivedClass1Property": "I am a Derived1", 

 "BaseProperty": "Base1", 

 "TypeOfObject": 0 

 }, 

 { 

 "DerivedClass2Property": "I am a Derived2", 

 "BaseProperty": "Base2", 

 "TypeOfObject": 1 

 } 

 ] 
} 

I realize that during de-serialization, by default, JsonConvert is simply going to create instances of BaseClass during de-serialization of the ClassArray property. So my thought is that I need to be able to intercept the de-serialization of the ClassArray property, determine the derived type that needs to be created by examining the value of the TypeOfObject property, and then return that type. I've tried creating my own converter that inherits from CustomConverter, but I cannot seem to make it work. Can anyone recommend a strategy for doing what I describe? Please provide a code snippet, if possible.  


Here is my code for the classes being serialized:

  
public class ContainerClass
    {
        private BaseClass[] classArray;

        public ContainerClass(int capacity)
        {
            classArray = new BaseClass[capacity];
        }

        public string SomePropertyToSerialize { get; set; }

        public BaseClass[] ClassArray { get { return classArray; } set { classArray = value; } }

    }

public class BaseClass
    {
        protected ObjectType typeOfObject = ObjectType.Derived1;
        public string BaseProperty { get; set; }

        public ObjectType TypeOfObject { get { return typeOfObject; } set { typeOfObject = value; } }
    }

    public class DerivedClass1 : BaseClass
    {
        public string DerivedClass1Property { get; set; }


    }

    public class DerivedClass2 : BaseClass
    {
        public string DerivedClass2Property { get; set; }

        public DerivedClass2()
        {
            typeOfObject = ObjectType.Derived2;
        }


    }

    public enum ObjectType
    {
        Derived1,
        Derived2
    }

Apr 23, 2010 at 5:05 PM
Edited Apr 23, 2010 at 5:06 PM

Okay, so here is the solution. No CustomCreationConverter is necessary. All you have to do is make sure that you specify JsonSerializerSettings and set the TypeNameHandling property value to TypeNameHandling.Objects when you serialize and de-serialize, as follows:

 

//Serialization
json = JsonConvert.SerializeObject(container, Formatting.Indented,new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Objects});

//De-Serialization
 ContainerClass container2 = JsonConvert.DeserializeObject<ContainerClass>(json,new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Objects});
Apr 27, 2010 at 7:58 PM
Edited Apr 27, 2010 at 7:59 PM

I am running into the same situation, except that I can't benefit from the JsonSerializerSettings and TypeNameHandling property because the JSON string I am dealing with is generated at the client and knows nothing about the backend class I have constructed for it.

I would be interested to see what you came up with for a CustomConverter, regardless if it works or not. 

Thanks.

 

 

Apr 28, 2010 at 1:59 AM
How are you deserializing your json string without the client having reference to the type being created?

Sent from my iPod

On Apr 27, 2010, at 3:58 PM, "westchamp24" <notifications@codeplex.com> wrote:

From: westchamp24

I am running into the same situation, except that I can't benefit from the JsonSerializerSettings and TypeNameHandling property because the JSON string I am dealing with is generated at the client and knows nothing about the backend class I have constructed for it.

I would be interested to see your what you came up with for a CustomConverter, regardless if it works or not.

Thanks.

Apr 28, 2010 at 11:47 AM

The json string is generated in a Flex client, by a third party api.  I am then sending that string to my custom service, where I do some additional processing.  I have created my own set of .NET classes for this json object and processing, which are totally independent of the flex api that generated the json.

Correct me if I am wrong, but I believe the TypeNameHanding property requires the .NET object type as a prefix to the json object, which is not possible in my case.     

Apr 30, 2010 at 2:32 AM
Yes, you are correct about the TypeNameHandling: it does require the .Net type name in the json string in order to deserialize correctly.

In my case, what I am doing is requiring the sender to simply inject the full type name in the string before he sends it. The class names on my end exactly match the ones on his end, and, in my request, I simply pass him the namespave and assembly name that I want him to inject in his response.

Would that work in your case? If not then I'll try to find a little time to look at the Json.net source and see what it takes to write a custom converter, since you don't seem to be getting much help from this forum. :-/

Sent from my iPod

On Apr 28, 2010, at 7:47 AM, "westchamp24" <notifications@codeplex.com> wrote:

From: westchamp24

The json string is generated in a Flex client, by a third party api. I am then sending that string to my custom service, where I do some additional processing. I have created my own set of .NET classes for this json object and processing, which are totally independent of the flex api that generated the json.

Correct me if I am wrong, but I believe the TypeNameHanding property requires the .NET object type as a prefix to the json object, which is not possible in my case.

Apr 30, 2010 at 10:49 AM

That is actually a pretty decent solution for my situation.  The JSON object itself is pretty simple, about 5 properties, and not nearly the level of nesting I have seen in some other json objects.

Thanks.