Motivation: Wanted convenience of a Dictionary on the server side MVC controller (for some key look-up based logic), yet send the same list of objects down to Knockout Ajax client, which most readily consumes lists as Javascript object arrays.
Could’ve just exposed the List
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace YouNameIt {
using CartItemDict = Dictionary<long, CartItemDto>;
//reverse of this: https://stackoverflow.com/questions/24759181/deserializing-a-json-dictionaryint-customtype-to-listcustomtype
//adapted from here: https://james.newtonking.com/json/help/index.html?topic=html/CustomJsonConverter.htm
public class DictToListConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof (Dictionary<object, object>);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var t = JToken.FromObject(value);
if (t.Type != JTokenType.Object)
{
t.WriteTo(writer);
}
else
{
var o = (JObject) t;
var values = o.Properties().Select(p => p.Value).ToList();
(new JArray(values)).WriteTo(writer);
}
}
}
public class CartDto
{
[JsonConverter(typeof(DictToListConverter))]
public CartItemDict Items { get; set; }
[DataType(DataType.Currency)]
public decimal TotalPrice { get; private set; }
}
public class CartItemDto : VariantDto
{
public long CartItemId { get; private set; }
public int Quantity { get; private set; }
[DataType(DataType.Currency)]
public decimal UnitPrice { get; private set; }
[DataType(DataType.Currency)]
public decimal LinePrice { get; private set; }
private List _addons;
public List Addons { get { return _addons ?? (_addons = new List()); } }
}
}