2

I have the following C# code, using Newtonsoft.Json v6.0.6:

void Main() {
    var data=new AllData();
    var cst=new CustomerData();
    cst.CustomerName="Customer1";
    cst.Add(1, new UserData() {UserName="User1", UserPhone="123456789"});
    cst.Add(2, new UserData() {UserName="User2", UserPhone="987654321"});
    data.Add(1, cst);

    string json = Newtonsoft.Json.JsonConvert.SerializeObject(data, Newtonsoft.Json.Formatting.Indented);
    Console.WriteLine(json);
}

public class UserData {
    public string UserName;
    public string UserPhone;
}

public class CustomerData:Dictionary<int,UserData> {
    public string CustomerName;
}

public class AllData:Dictionary<int,CustomerData> {}

So from this code I'm expecting to see this output:

  {
    "1": {
      "CustomerName": "Customer1",
      "1": {
        "UserName": "User1",
        "UserPhone": "123456789"
      },
    "2": {
      "UserName": "User2",
      "UserPhone": "987654321"
      }
    }
  }

But instead I'm seeing:

{
  "1": {
    "1": {
      "UserName": "User1",
      "UserPhone": "123456789"
    },
  "2": {
    "UserName": "User2",
    "UserPhone": "987654321"
    }
  }
}

i.e. My CustomerName property is ignored.

I've played with the Newtonsoft.Json.MemberSerialization and Newtonsoft.Json.JsonProperty attributes without success and so am wondering where to look now. A full custom serialisation implementation seems like overkill, is there a simple way to solve this?

Elliveny
  • 2,159
  • 1
  • 20
  • 28
  • 1
    http://stackoverflow.com/questions/14383736/json-net-with-custom-collection-with-collection-properties –  Feb 03 '16 at 11:04
  • Inheriting from `List` or `Dictionary` is considered code smell. Is there any reason you couldn't get away without inheriting `Dictionary`? – Gediminas Masaitis Feb 03 '16 at 11:05
  • @AndyJ - I'm aware of custom serialization, it seems like there should be a simpler way though, hence my question – Elliveny Feb 03 '16 at 11:11
  • @GediminasMasaitis I could have a property for the dictionary, but this makes the Json serialization more complex as I'd want to omit the property name. I could have a private dictionary and have my own accessor methods but that complicates my example, so I chose inheritance to demonstrate the issue – Elliveny Feb 03 '16 at 11:14
  • Would JsonExtensionDataAttribute be suitable? http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonExtensionDataAttribute.htm http://stackoverflow.com/questions/14893614/how-to-serialize-a-dictionary-as-part-of-its-parent-object-using-json-net –  Feb 03 '16 at 11:19
  • @AndyJ It appears that JsonExtensionDataAttribute is just for deserialization... unless I'm missing something? – Elliveny Feb 03 '16 at 13:00
  • The first bit of text in that link says it does both :S "Instructs the JsonSerializer to deserialize properties with no matching class member into the specified collection and write values during serialization." –  Feb 03 '16 at 13:06
  • @GediminasMasaitis Can you add a reference to why it would be considered a code smell? I would love to read more about it. – span Feb 15 '18 at 13:35

1 Answers1

4

You can use the JsonExtensionDataAttribute that JSON.Net provides to put any properties that don't exist on the parent object in to the collection property.

Here's an example taken from another SO post.

JSON:

{
    "X" : "value",
    "key1": "value1",
    "key2": "value2"
}

C# Data Object:

public class Test
{
    public string X { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> Y { get; set; }
}

Key1 and Key2 will end up in the Dictionary because they don't exist in the class "Test, where as X will end up in the X property.

It's not perfect, it seems you have to have a Dictionary of type Dictionary, but it still might be a better option that using a custom serializer?

Here's an example on DotNetFiddle using one level of your data classes.

For the data:

public class UserData
{
    public string UserName;
    public string UserPhone;
}

public class CustomerData
{
    public string CustomerName;

    [JsonExtensionData]
    public Dictionary<string, object> Users;
}

var data = new CustomerData()
{
    CustomerName = "Foo",
    Users = new Dictionary<string, object>() 
    {
        { "1",  new UserData() { UserName = "Fireman", UserPhone = "0118 999 881 999 119 725 ... 3" } },
        { "2",  new UserData() { UserName = "Jenny", UserPhone = "867-5309" } }
    }
};

It produces the JSON:

{
    "customerName": "Foo",
    "1": {
        "userName": "Fireman",
        "userPhone": "0118 999 881 999 119 725 ... 3"
    },
    "2": {
        "userName": "Jenny",
        "userPhone": "867-5309"
    }
}
Community
  • 1
  • 1