enorl76
enorl76

Reputation: 2655

How to model JSON with named properties on a common type

Here's sample JSON:

{
    "notifications": [
        {
            "Profile.Guestbook.Post": {
                "TargetIntId": 1,
                "Digest": true,
                "DigestSchedule": "00 * * * * *"
            },
            "Profile.MediaEntry.Post": {
                "TargetIntId": 1,
                "Digest": true,
                "DigestSchedule": "00 * * * * *"
            }
        }
    ]
} 

I'm trying to serialize into C# classes, where the NotificationInfo instance's EventName is the value of the keys, event.namespace1 and event2.namespaceX

public class Preferences 
{
    public List<NotificationInfo> Notifications { get;set; }
}

public class NotificationInfo
{
    public string EventName { get;set; }
    public int TargetIntId { get;set; }
    public bool Digest { get;set; }
}

I created a dotnetfiddle: https://dotnetfiddle.net/8oqniT

Upvotes: 1

Views: 67

Answers (1)

Brian Rogers
Brian Rogers

Reputation: 129707

The easiest way to get things working is to change your model to the following:

public class Preferences
{
    public List<Dictionary<string, NotificationInfo>> Notifications { get; set; }
}

public class NotificationInfo
{
    public int TargetIntId { get; set; }
    public bool Digest { get; set; }
}

The event names from the JSON will be become the keys of the dictionary in the list.

Fiddle: https://dotnetfiddle.net/P3yD3p

However, this model can be a little bit awkward to use, as you can see from the fiddle. A better approach, in my opinion, is to keep your original model in place and use a custom JsonConverter to handle the translation. Here is the code you would need for the converter:

public class NotificationsConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(List<NotificationInfo>);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var array = JArray.Load(reader);
        return array.Children<JObject>()
                    .SelectMany(jo => jo.Properties())
                    .Select(jp => new NotificationInfo
                    {
                        EventName = jp.Name,
                        TargetIntId = (int)jp.Value["TargetIntId"],
                        Digest = (bool)jp.Value["Digest"]
                    })
                    .ToList();
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

To use it, just add a [JsonConverter] attribute to your Notifications property like this:

    [JsonConverter(typeof(NotificationsConverter))]
    public List<NotificationInfo> Notifications { get; set; }

Fiddle: https://dotnetfiddle.net/vkjXC0

Upvotes: 2

Related Questions