How to serialize ExpandoObject using ServiceStack JsonSerializer?
Asked Answered
B

1

6

Is it possible to get the ServiceStack JsonSerializer to serialize an ExpandoObject as a flat object rather than a dictionary? Something roughly approximate to this:

{"x":"xvalue","y":"\/Date(1313966045485)\/"}

I am trying to compare JSON serialization of ExpandoObject using three different systems: the .NET BCL JavaScriptSerializer, Newtonsoft JSON.NET, and ServiceStack's JSON offering.

I start with a fairly simple dynamic object.

dynamic test = new ExpandoObject();
test.x = "xvalue";
test.y = DateTime.Now;

It seems simpler for a serializer to treat an ExpandoObject as a IDictionary<string, object>. Both BCL and ServiceStack start off this way, though going fairly different routes with the result.

JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
Console.WriteLine(javaScriptSerializer.Serialize(test));
// [{"Key":"x","Value":"xvalue"},{"Key":"y","Value":"\/Date(1313966045485)\/"}]

Console.WriteLine(ServiceStack.Text.JsonSerializer.SerializeToString(test));
// ["[x, xvalue]","[y, 8/21/2011 16:59:34 PM]"]

I would prefer to have ExpandoObject serialized more as it is assembled in code, like a typical class would be serialized. You can add an override JavaScript serializer to the BCL system for IDictionary<string, object>. This works great, assuming one doesn't actually have a IDictionary<string, object> that needs to stay that way (which I don't yet).

JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
javaScriptSerializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJsonConverter() });
Console.WriteLine(javaScriptSerializer.Serialize(test));
// {"x":"xvalue","y":"\/Date(1313966045485)\/"}

Unfortunately, I still need a way to get ServiceStack's JsonSerializer to treat an ExpandoObject in the same fashion. How do I hook into the ServiceStack system to make this possible?

Update: While it isn't an option for my uses, it looks like ServiceStack handles anonymous objects just fine.

Console.WriteLine(ServiceStack.Text.JsonSerializer.SerializeToString(new { x = "xvalue", y = DateTime.Now }));
// {"x":"xvalue","y":"\/Date(1313980029620+0000)\/"}
Bainbridge answered 21/8, 2011 at 23:12 Comment(0)
H
1

There aren't any hooks available in ServiceStack's JsonSerializer that you can plug into to change this behaviour but I'm be more than happy to take a pull request that does it ;)

The classes you will need to change are:

  • JsWriter.cs (Line 223) - insert code to detect an expando object and return a delegate that writes the expando object how you want it.
  • JsReader (Line 42) - insert code to detect an expando object and return a delegate to read the contents of a string and deserialize it back into an expando

I imagine the code for dealing with an expando object is similar to a dictionary so you should be able to use the Dictionary implementation classes to guide you (i.e. WriteDictionary.cs and DeserializeDictionary.cs)

Feel free to use the ServiceStack forum if you have any more questions/issues on this: https://groups.google.com/forum/#!forum/servicestack

Handset answered 22/8, 2011 at 4:25 Comment(3)
If I can get MonoTouch to use ServiceStack to deserialize JSON generated from one of the other systems, this specific problem won't actually hurt me too much. Even if I can work around it, I will try to see what I can do to put together some code for a pull request; it would be nice to use ServiceStack on both ends of my current project.Bainbridge
Sure, to get ServiceStack working on MonoTouch you just need to use the MonoTouch build which is available at: github.com/ServiceStack/ServiceStack/tree/master/release/latest/…Handset
That was easy. I had it up and running in a few minutes. It would have been seconds if I wasn't relearning keyboard shortcuts in MonoDevelop as I went.Bainbridge

© 2022 - 2024 — McMap. All rights reserved.