using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
internal class WhatToMineCalculatorsResponse
public IList<WhatToMineCalculatorResponse> Coins { get; set; }
internal class WhatToMineCalculatorResponse
public WhatToMineCalculatorResponse(string name)
public string Name { get { return _name; } }
public int Id { get; set; }
public string Symbol { get; set; }
public string Status { get; set; }
[JsonProperty("algorithm")]
public string Algo { get; set; }
public bool IsListed { get; set; }
internal class WhatToMineCalculatorResponseListConverter : KeyedListToJsonObjectConverterBase<WhatToMineCalculatorResponse>
protected override string KeyPropertyUnderlyingName
public abstract class KeyedListToJsonObjectConverterBase<T> : JsonConverter
public override bool CanConvert(Type objectType)
return typeof(IList<T>).IsAssignableFrom(objectType);
protected abstract string KeyPropertyUnderlyingName { get; }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
var itemContract = serializer.ContractResolver.ResolveContract(typeof(T)) as JsonObjectContract;
if (itemContract == null)
throw new JsonSerializationException(string.Format("type {0} is not serialized as a JSON object"));
var keyProperty = itemContract.Properties.Where(p => p.UnderlyingName == KeyPropertyUnderlyingName).SingleOrDefault();
throw new JsonSerializationException(string.Format("Key property {0} not found", KeyPropertyUnderlyingName));
if (reader.SkipComments().TokenType == JsonToken.Null)
if (reader.TokenType != JsonToken.StartObject)
throw new JsonSerializationException(string.Format("Unexpected token {0} at {1}", reader.TokenType, reader.Path));
var list = existingValue as ICollection<T> ?? (ICollection<T>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
switch (reader.TokenType)
case JsonToken.EndObject:
case JsonToken.PropertyName:
var name = (string)reader.Value;
var jItem = JObject.Load(reader);
jItem.Add(keyProperty.PropertyName, name);
list.Add(jItem.ToObject<T>(serializer));
throw new JsonSerializationException(string.Format("Unexpected token {0} at {1}", reader.TokenType, reader.Path));
throw new JsonSerializationException("Unclosed object at path: " + reader.Path);
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
var itemContract = serializer.ContractResolver.ResolveContract(typeof(T)) as JsonObjectContract;
if (itemContract == null)
throw new JsonSerializationException(string.Format("type {0} is not serialized as a JSON object"));
var keyProperty = itemContract.Properties.Where(p => p.UnderlyingName == KeyPropertyUnderlyingName).SingleOrDefault();
throw new JsonSerializationException(string.Format("Key property {0} not found", KeyPropertyUnderlyingName));
var converters = serializer.Converters.ToArray();
var list = (IEnumerable<T>)value;
writer.WriteStartObject();
foreach (var item in list)
var jItem = JObject.FromObject(item, serializer);
var name = (string)jItem[keyProperty.PropertyName];
jItem.Remove(keyProperty.PropertyName);
writer.WritePropertyName(name);
jItem.WriteTo(writer, converters);
public static partial class JsonExtensions
public static JsonReader SkipComments(this JsonReader reader)
while (reader.TokenType == JsonToken.Comment && reader.Read())
public static void ReadAndAssert(this JsonReader reader)
throw new ArgumentNullException();
new JsonReaderException(string.Format("Unexpected end at path {0}", reader.Path));
public static void Test()
var responseString = GetJSON();
var settings = new JsonSerializerSettings
Converters = { new WhatToMineCalculatorResponseListConverter() },
var root = JsonConvert.DeserializeObject<WhatToMineCalculatorsResponse>(responseString, settings);
var json3 = JsonConvert.SerializeObject(root, Formatting.Indented, settings);
Console.WriteLine("\nDeserialized and re-serialized {0} using WhatToMineCalculatorResponseListConverter when writing:", root);
Console.WriteLine(json3);
Assert.IsTrue(JObject.Parse(responseString)["coins"].Children().OfType<JProperty>().Select(p => p.Name)
.SequenceEqual(JObject.Parse(json3)["coins"].Children().OfType<JProperty>().Select(p => p.Name)));
var json2 = JsonConvert.SerializeObject(root, Formatting.Indented);
Console.WriteLine("\nDeserialized and re-serialized {0} without using WhatToMineCalculatorResponseListConverter when writing:", root);
Console.WriteLine(json2);
status: ""No available stats"",
algorithm: ""Scrypt-OG"",
status: ""No available stats"",
public static void Main()
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public class AssertionFailedException : System.Exception
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
public static class Assert
public static void IsTrue(bool value)
public static void IsTrue(bool value, string message)
throw new AssertionFailedException(message ?? "failed");