servicestackormlite-servicestackservicestack-text

ServiceStack ORMLite JSON Deserialization multiple levels


I've got a class containing a Dictionary like this:

Dictionary<string,object> Data

I put data on multiple levels into here, such as:

Data.Add("simple",4);
Data.Add("object",new Dictionary<string,object>{{"key",4}});
Data.Add("array",new List<string>{"a","b","c"});

Then I .Save() it with OrmLite, which is setup to use JSON instead of JSV:

SqliteDialect.Provider.StringSerializer = new JsonStringSerializer();

Looking inside the stored data, using SQL, it looks like perfectly valid JSON.

{
    "simple": 4,
    "object": {
        "key": 4
    },
    "array": [
        "a","b","c"
    ]
}

However, when I Load() the data back, it doesn't deserialize back to the original.

Here's a link to Gist Cafe, showing the problem: https://gist.cafe/9ed2bbb3a6a0348f129c493887ae8170


Solution

  • By default JsonStringSerializer uses ServiceStack.Text Typed JSON Serializer which can't deserialize an object back to its original type since that type information is lost, all it sees is the runtime object Type which it leaves as a string since it doesn't know what other object it should deserialize to.

    Which is why it's recommended that you serialize typed DTOs so the type information is preserved, e.g:

    class CustomData
    {
        public int Simple { get; set; }
        public Dictionary<string,int> Object { get; set; }
    }
    

    If you want to deserialize anonymous object data structures into untyped collections you can configure ServiceStack.Text to use JS Utils to handle deserializing arbitrary JSON into untyped data structures by registering it with:

    ServiceStack.JS.Configure();
    

    Which I've done in this modified gist:

    https://gist.cafe/953f2da51a5077ecf7b5109c14ec2c32

    Which outputs the expected result:

    {
        Id: 1,
        Data: 
        {
            simple: 4,
            object: 
            {
                key: 4
            },
            array: 
            [
                a,
                b,
                c
            ]
        }
    }
    

    Whilst it works in this instance because you're using only serializing JSON data types, it wont work if your object dictionary contains complex types because all JS Utils can see is the raw JSON string without any type information, so it's only able to deserialize into untyped collections that matches the JSON object - which is why it's recommended to serialize Typed DTOs so the types are preserved.