CSharp · Console
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
internal class WhatToMineCalculatorsResponse
{
// Should be Dictionary???
[JsonProperty("coins")]
public IList<WhatToMineCalculatorResponse> Coins { get; set; }
}
internal class WhatToMineCalculatorResponse
{
readonly string _name;
public WhatToMineCalculatorResponse(string name)
{
this._name = name;
}
// I want the key set in this field
public string Name { get { return _name; } }
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("tag")]
public string Symbol { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("algorithm")]
public string Algo { get; set; }
[JsonProperty("listed")]
public bool IsListed { get; set; }
}
internal class WhatToMineCalculatorResponseListConverter : KeyedListToJsonObjectConverterBase<WhatToMineCalculatorResponse>
{
protected override string KeyPropertyUnderlyingName // => nameof(WhatToMineCalculatorResponse.Name);
{
get { return "Name"; }
}
}
public abstract class KeyedListToJsonObjectConverterBase<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
if (objectType.IsArray)
return false;
return typeof(IList<T>).IsAssignableFrom(objectType);
}
protected abstract string KeyPropertyUnderlyingName { get; }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
// Get the key property name from the underlying name
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();
if (keyProperty == null)
throw new JsonSerializationException(string.Format("Key property {0} not found", KeyPropertyUnderlyingName));
// Validate initial token.
if (reader.SkipComments().TokenType == JsonToken.Null)
return null;
if (reader.TokenType != JsonToken.StartObject)
throw new JsonSerializationException(string.Format("Unexpected token {0} at {1}", reader.TokenType, reader.Path));
// Allocate the List<T>. (It might be some subclass of List<T>, so use the default creator.
var list = existingValue as ICollection<T> ?? (ICollection<T>)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
// Process each key/value pair.
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
case JsonToken.EndObject:
return list;
case JsonToken.PropertyName:
{
// Get the name.
var name = (string)reader.Value;
reader.ReadAndAssert();
// Load the object
var jItem = JObject.Load(reader);
// Add the name property
jItem.Add(keyProperty.PropertyName, name);
// Deserialize the item and add it to the list.
list.Add(jItem.ToObject<T>(serializer));
}
break;
default:
{
throw new JsonSerializationException(string.Format("Unexpected token {0} at {1}", reader.TokenType, reader.Path));
}
}
}
// Should not come here.
throw new JsonSerializationException("Unclosed object at path: " + reader.Path);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Get the key property name from the underlying name
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();
if (keyProperty == null)
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);
}
writer.WriteEndObject();
}
}
public static partial class JsonExtensions
{
public static JsonReader SkipComments(this JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment && reader.Read())
;
return reader;
}
public static void ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
{
new JsonReaderException(string.Format("Unexpected end at path {0}", reader.Path));
}
}
}
class TestClass
{
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);
}
static string GetJSON()
{
var json = @"{
coins: {
365Coin: {
id: 74,
tag: ""365"",
algorithm: ""Keccak"",
lagging: true,
listed: false,
status: ""No available stats"",
testing: false
},
Aiden: {
id: 65,
tag: ""ADN"",
algorithm: ""Scrypt-OG"",
lagging: true,
listed: false,
status: ""No available stats"",
testing: false
},
Adzcoin: {
id: 157,
tag: ""ADZ"",
algorithm: ""X11"",
lagging: false,
listed: false,
status: ""Active"",
testing: false
}
}
}";
return json;
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine();
try
{
TestClass.Test();
}
catch (Exception ex)
{
Console.WriteLine("Failed with unhandled exception: ");
Console.WriteLine(ex);
throw;
}
}
}
public class AssertionFailedException : System.Exception
{
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
}
public static class Assert
{
public static void IsTrue(bool value)
{
IsTrue(value, "failed");
}
public static void IsTrue(bool value, string message)
{
if (value == false)
throw new AssertionFailedException(message ?? "failed");
}
}