gotnull
gotnull

Reputation: 27214

Construct JSON payload

I have the following table:

Table

I'd like to execute a LINQ Query that serializes:

JSON:

{
  "product-list": {
    "products": [
        {
          "P_Flavor": [
            "Berry",
            "Cedar",
            "Cherry",
            "Coffee"
          ],
          "P_Winery": [
            "Lyeth"
          ],
          "P_Body": [
            "Elegant",
            "Firm",
            "Firm Tannins",
            "Polished",
            "Supple",
            "Tannins"
          ],
          "P_Name": "A Red Blend",
          "P_DateReviewed": "08/31/95",
          "P_WineID": 34699,
          "P_Score": 5,
        }
    ]
  }
}

I would normally use JavaScriptSerializer to do this, however I would like to construct my own JSON payload.

IList<record_property> recList = (from c in entities.record_property
                                    select c).ToList();

var json = new JavaScriptSerializer().Serialize(recList);

What would be the best way to do this?

Upvotes: 0

Views: 1652

Answers (1)

Patrick Quirk
Patrick Quirk

Reputation: 23747

There may be a quicker/more concise way to do this, but I did it by combining a JavaScriptConverter with a helper type.

The converter (simpler than it looks, inspired from here):

private class RecordPropertyJavaScriptConverter : JavaScriptConverter
{
    private static readonly Type[] _supportedTypes = new[]
    {
        typeof(record_group)
    };

    public override IEnumerable<Type> SupportedTypes
    {
        get { return _supportedTypes; }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (type == typeof(record_group))
        {
            record_group obj = new record_group();

            var kvp = dictionary.Single();

            obj.Key = kvp.Key;
            obj.Values = serializer.ConvertToType<IEnumerable<object>>(kvp.Value);

            return obj;
        }

        return null;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        var dataObj = obj as record_group;
        if (dataObj != null)
        {
            return new Dictionary<string, object>
            {
                {dataObj.Key,  dataObj.Values}
            };
        }
        return new Dictionary<string, object>();
    }
}

The helper type:

private class record_group
{
    public string Key;
    public IEnumerable<object> Values;
}

The serialization code:

var groups = recList.GroupBy(r => r.Key)
                    .Select(g => new record_group { Key = g.Key, Values = g.Select(r => r.Value) });

JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new [] {new RecordPropertyJavaScriptConverter()});
string json = serializer.Serialize(groups);

The output (with some tabs, newlines added by me):

[{"P_Flavor":["Berry","Cedar","Cherry","Coffee"]},
 {"P_Winery":["Lyeth"]},
 {"P_Body":["Elegant","Firm","Firm Tannins","Polished","Supple","Tannins"]},
 {"P_Name":["A Red Blend"]},
 {"P_DateReviewed":["08/31/95"]},
 {"P_WineID":[34699]},
 {"P_Score":[5]}]

Deserialization can then be done (using the same serializer instance from above) as follows:

var deserialized = serializer.Deserialize<IEnumerable<record_group>>(json);
var properties = deserialized.SelectMany(g => g.Values.Select(v => new record_property { Key = g.Key, Value = v }));

Upvotes: 1

Related Questions