3

just trying to work out how well servicestack.text supports serializing expando objects to and from json. I know that an expando object implements an IDictionary. When I serialize to and from json I am having trouble getting the correct types in the deserialized IDictionary. As Json does not support types natively and servicestack has a setting called JsConfig.IncludeTypeInfo I expected it to include the type information in the serialized json to enable service stack to deserialize to the correct types on the other side, (eg a decimal without decimal places is deserialized to a uint64).

Is there anyway to force servicestack to correctly deserialize the same types as the source using an expando object ?

Ps: I do not want to use a poco object to achieve this as I do not know the properties of the object until runtime.

Below is a quick test showing what I mean.

Thanks

/// <summary>
/// Test servicestack serialisation
/// I was expecting that IncludeTypeInfo=true would always add the type info
/// so when you deserialise into a IDictionary<string,object> servicerstack
/// would have enough information to convert to the expected type
/// </summary>
[Test]
public void TestDynamicSerialization()
{
    JsConfig.Reset();
    JsConfig.IncludeNullValues = true;
    JsConfig.IncludeTypeInfo = true;
    JsConfig.EmitCamelCaseNames = false;
    JsConfig.ConvertObjectTypesIntoStringDictionary = true;
    JsConfig.PropertyConvention = JsonPropertyConvention.Lenient;
    JsConfig.TryToParsePrimitiveTypeValues = true;

    // create an expando object
    dynamic obj = new ExpandoObject();

    // cast as a idictionary and set two decimals, one with decimnal places and one without
    var objDict = (IDictionary<string, object>)obj;
    objDict["decimal1"] = 12345.222M;
    objDict["decimal2"] = 12345M;

    Assert.AreEqual(typeof(decimal), objDict["decimal1"].GetType());
    Assert.AreEqual(typeof(decimal), objDict["decimal2"].GetType());

    // serialise to json
    var json = JsonSerializer.SerializeToString(obj);

    //deserialise to a a IDictionary<string,object>
    var deserialisedDict = JsonSerializer.DeserializeFromString<IDictionary<string, object>>(json);

    // make sure we got the expected types
    Assert.AreEqual(typeof(decimal), deserialisedDict["decimal1"].GetType());
    Assert.AreEqual(typeof(decimal), deserialisedDict["decimal2"].GetType(), "Fails because type is UInt64 expected decimal");


}
user1661621
  • 797
  • 9
  • 15

2 Answers2

1

The ServiceStack.Text on NuGet is a .NET 3.5 dll and has no implicit support for Dynamic/Expando. You can still use the JsonObject to dynamically parse JSON.

In a .NET 4.0 build of ServiceStack.Text you can use DynamicJson which wraps access to a JSON object in a Dynamic class.

mythz
  • 141,670
  • 29
  • 246
  • 390
  • I change the deserialization to JsonObject but as I expected it did not know the correct type of the type and teh decimal fields are of type string. var deserialisedDict = JsonSerializer.DeserializeFromString(json); I might try Json.Net to see if it can do a better job of deserializing dynamic objects and the types of their properties. – user1661621 Dec 06 '12 at 01:39
1

Should be fixed as of https://github.com/ServiceStack/ServiceStack.Text/pull/347 decimals will come back by default unless you specify TryToParseNumericType in which case you'll get the best fitting number type.

Antony Denyer
  • 1,541
  • 1
  • 15
  • 31