tags:

views:

150

answers:

2

I'm trying to serialize/deserialize a Dictionary<string, object> which seems to work fine if the object is a simple type but doesn't work when the object is more complex.

I have this class:

public class UrlStatus
{
 public int Status { get; set; }
 public string Url { get; set; }
}

In my dictionary I add a List<UrlStatus> with a key of "Redirect Chain" and a few simple strings with keys "Status", "Url", "Parent Url". The string I'm getting back from JSON.Net looks like this:

{"$type":"System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib","Status":"OK","Url":"http://www.ehow.com/m/how_5615409_create-pdfs-using-bean.html","Parent Url":"http://www.ehow.com/mobilearticle35.xml","Redirect Chain":[{"$type":"Demand.TestFramework.Core.Entities.UrlStatus, Demand.TestFramework.Core","Status":301,"Url":"http://www.ehow.com/how_5615409_create-pdfs-using-bean.html"}]}

The code I'm using to serialize looks like:

JsonConvert.SerializeObject(collection, Formatting.None, new JsonSerializerSettings 
{ 
 TypeNameHandling = TypeNameHandling.Objects, 
 TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple 
});

to deserialize I'm doing:

JsonConvert.DeserializeObject<T>(collection, new JsonSerializerSettings
{
 TypeNameHandling = TypeNameHandling.Objects,
 TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple, 
});

The Dictionary comes back fine, all the strings come back fine, but the List doesn't get properly deserialized. It just comes back as

{[
  {
    "$type": "XYZ.TestFramework.Core.Entities.UrlStatus, XYZ.TestFramework.Core",
    "Status": 301,
    "Url": "/how_5615409_create-pdfs-using-bean.html"
  }
]}

Of course I can deserailize this string again and I get the correct object, but it seems like JSON.Net should have done this for me. Clearly I'm doing something wrong, but I don't know what it is.

Can anyone help?

Thanks, Dan

+1  A: 

I think that is a bug in an older version of Json.NET. If you aren't already using the latest version, upgrade and try again.

    public class UrlStatus
    {
      public int Status { get; set; }
      public string Url { get; set; }
    }


    [Test]
    public void GenericDictionaryObject()
    {
      Dictionary<string, object> collection = new Dictionary<string, object>()
        {
          {"First", new UrlStatus{ Status = 404, Url = @"http://www.bing.com"}},
          {"Second", new UrlStatus{Status = 400, Url = @"http://www.google.com"}},
          {"List", new List<UrlStatus>
            {
              new UrlStatus {Status = 300, Url = @"http://www.yahoo.com"},
              new UrlStatus {Status = 200, Url = @"http://www.askjeeves.com"}
            }
          }
        };

      string json = JsonConvert.SerializeObject(collection, Formatting.Indented, new JsonSerializerSettings
      {
        TypeNameHandling = TypeNameHandling.All,
        TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
      });

      Assert.AreEqual(@"{
  ""$type"": ""System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib"",
  ""First"": {
    ""$type"": ""Newtonsoft.Json.Tests.Serialization.TypeNameHandlingTests+UrlStatus, Newtonsoft.Json.Tests"",
    ""Status"": 404,
    ""Url"": ""http://www.bing.com""
  },
  ""Second"": {
    ""$type"": ""Newtonsoft.Json.Tests.Serialization.TypeNameHandlingTests+UrlStatus, Newtonsoft.Json.Tests"",
    ""Status"": 400,
    ""Url"": ""http://www.google.com""
  },
  ""List"": {
    ""$type"": ""System.Collections.Generic.List`1[[Newtonsoft.Json.Tests.Serialization.TypeNameHandlingTests+UrlStatus, Newtonsoft.Json.Tests]], mscorlib"",
    ""$values"": [
      {
        ""$type"": ""Newtonsoft.Json.Tests.Serialization.TypeNameHandlingTests+UrlStatus, Newtonsoft.Json.Tests"",
        ""Status"": 300,
        ""Url"": ""http://www.yahoo.com""
      },
      {
        ""$type"": ""Newtonsoft.Json.Tests.Serialization.TypeNameHandlingTests+UrlStatus, Newtonsoft.Json.Tests"",
        ""Status"": 200,
        ""Url"": ""http://www.askjeeves.com""
      }
    ]
  }
}", json);

      object c = JsonConvert.DeserializeObject(json, new JsonSerializerSettings
      {
        TypeNameHandling = TypeNameHandling.All,
        TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
      });

      Assert.IsInstanceOfType(typeof(Dictionary<string, object>), c);

      Dictionary<string, object> newCollection = (Dictionary<string, object>)c;
      Assert.AreEqual(3, newCollection.Count);
      Assert.AreEqual(@"http://www.bing.com", ((UrlStatus)newCollection["First"]).Url);

      List<UrlStatus> statues = (List<UrlStatus>) newCollection["List"];
      Assert.AreEqual(2, statues.Count);
    }
  }

Edit, I just noticed you mentioned a list. TypeNameHandling should be set to All.

James Newton-King
I'm using Json.NET 3.5 Release 8. I even downloaded the zip again to be sure.
Dan at Demand
Just tried the latest build 53965, still didn't work.
Dan at Demand
TypeNameHandling = TypeNameHandling.All was the trick.
Dan at Demand
+1  A: 

If you continue to have issues you could also try ServiceStack's JSON Serializer which also supports Deserializing Dictionary<string,object>:

var urlStatus = new UrlStatus
{
 Status = 301,
 Url = "http://www.ehow.com/how_5615409_create-pdfs-using-bean.html",
};

var map = new Dictionary<string, object>
{
 {"Status","OK"},
 {"Url","http://www.ehow.com/m/how_5615409_create-pdfs-using-bean.html"},
 {"Parent Url","http://www.ehow.com/mobilearticle35.xml"},
 {"Redirect Chai", urlStatus},
};

var json = JsonSerializer.SerializeToString(map);
var fromJson = JsonSerializer.DeserializeFromString<Dictionary<string, object>>(json);

Assert.That(fromJson["Status"], Is.EqualTo(map["Status"]));
Assert.That(fromJson["Url"], Is.EqualTo(map["Url"]));
Assert.That(fromJson["Parent Url"], Is.EqualTo(map["Parent Url"]));

var actualStatus = JsonSerializer.DeserializeFromString<UrlStatus>((string)fromJson["Redirect Chai"]);
Assert.That(actualStatus.Status, Is.EqualTo(urlStatus.Status));
Assert.That(actualStatus.Url, Is.EqualTo(urlStatus.Url));

Console.WriteLine("JSON: " + json);

Which outputs:

JSON: {"Status":"OK","Url":"http://www.ehow.com/m/how_5615409_create-pdfs-using-bean.html","Parent Url":"http://www.ehow.com/mobilearticle35.xml","Redirect Chai":{"Status":301,"Url":"http://www.ehow.com/how_5615409_create-pdfs-using-bean.html"}}
mythz
I've already invested a lot of energy into JSON.NET, but your ServiceStack looks very interesting. I'm going to investigate it later. Thanks!
Dan at Demand