using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Text.Json.Serialization;
public class MarsWheather {
[JsonPropertyName("First_UTC")]
public DateTime FirstUTC { get; set; }
[JsonPropertyName("Last_UTC")]
public DateTime LastUTC { get; set; }
[JsonPropertyName("Season")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public Season MarsSeason { get; set; }
[JsonPropertyName("PRE")]
public DataDescription AtmosphericPressure { get; set; }
public class DataDescription{
public double Average { get; set; }
public double TotalCount { get; set; }
public double Minimum { get; set; }
public double Maximum { get; set; }
[JsonConverter(typeof(MarsWheatherRootObjectConverter))]
public class MarsWheatherRootObject
public Dictionary<string, MarsWheather> MarsWheathers { get; } = new Dictionary<string, MarsWheather>();
public class MarsWheatherRootObjectConverter : FixedAndvariablePropertyNameObjectConverter<MarsWheatherRootObject, Dictionary<string, MarsWheather>, MarsWheather>
static readonly Dictionary<string, ReadFixedKeyMethod> FixedKeyReadMethods = new Dictionary<string, ReadFixedKeyMethod>(StringComparer.OrdinalIgnoreCase)
{ "sol_keys", (ref Utf8JsonReader reader, MarsWheatherRootObject obj, string name, JsonSerializerOptions options) => reader.Skip() },
{ "validity_checks", (ref Utf8JsonReader reader, MarsWheatherRootObject obj, string name, JsonSerializerOptions options) => reader.Skip() },
protected override Dictionary<string, MarsWheather> GetDictionary(MarsWheatherRootObject obj) => obj.MarsWheathers;
protected override void SetDictionary(MarsWheatherRootObject obj, Dictionary<string, MarsWheather> dictionary) => throw new RowNotInTableException();
protected override bool TryGetFixedKeyReadMethod(string name, JsonSerializerOptions options, out ReadFixedKeyMethod method) => FixedKeyReadMethods.TryGetValue(name, out method);
protected override IEnumerable<KeyValuePair<string, WriteFixedKeyMethod>> GetFixedKeyWriteMethods(JsonSerializerOptions options) => Enumerable.Empty<KeyValuePair<string, WriteFixedKeyMethod>>();
public abstract class FixedAndvariablePropertyNameObjectConverter<TObject, TDictionary, TValue> : JsonConverter<TObject>
where TDictionary : class, IDictionary<string, TValue>, new()
protected delegate void ReadFixedKeyMethod(ref Utf8JsonReader reader, TObject obj, string name, JsonSerializerOptions options);
protected delegate void WriteFixedKeyMethod(Utf8JsonWriter writer, TObject value, JsonSerializerOptions options);
protected abstract TDictionary GetDictionary(TObject obj);
protected abstract void SetDictionary(TObject obj, TDictionary dictionary);
protected abstract bool TryGetFixedKeyReadMethod(string name, JsonSerializerOptions options, out ReadFixedKeyMethod method);
protected abstract IEnumerable<KeyValuePair<string, WriteFixedKeyMethod>> GetFixedKeyWriteMethods(JsonSerializerOptions options);
public override TObject Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
if (reader.TokenType == JsonTokenType.Null)
return (typeToConvert.IsValueType && Nullable.GetUnderlyingType(typeToConvert) == null)
? throw new JsonException(string.Format("Unepected token {0}", reader.TokenType))
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException(string.Format("Unepected token {0}", reader.TokenType));
var dictionary = GetDictionary(obj);
var valueConverter = (typeof(TValue) == typeof(object) ? null : (JsonConverter<TValue>)options.GetConverter(typeof(TValue)));
if (reader.TokenType == JsonTokenType.PropertyName)
var name = reader.GetString();
if (TryGetFixedKeyReadMethod(name, options, out var method))
method(ref reader, obj, name, options);
SetDictionary(obj, dictionary = new TDictionary());
dictionary.Add(name, valueConverter.ReadOrDeserialize(ref reader, typeof(TValue), options));
else if (reader.TokenType == JsonTokenType.EndObject)
throw new JsonException(string.Format("Unepected token {0}", reader.TokenType));
throw new JsonException();
public override void Write(Utf8JsonWriter writer, TObject value, JsonSerializerOptions options)
writer.WriteStartObject();
var dictionary = GetDictionary(value);
var valueConverter = (typeof(TValue) == typeof(object) ? null : (JsonConverter<TValue>)options.GetConverter(typeof(TValue)));
foreach (var pair in dictionary)
writer.WritePropertyName(pair.Key);
valueConverter.WriteOrSerialize(writer, pair.Value, typeof(TValue), options);
foreach (var pair in GetFixedKeyWriteMethods(options))
writer.WritePropertyName(pair.Key);
pair.Value(writer, value, options);
public static partial class JsonExtensions
public static void WriteOrSerialize<T>(this JsonConverter<T> converter, Utf8JsonWriter writer, T value, Type type, JsonSerializerOptions options)
converter.Write(writer, value, options);
JsonSerializer.Serialize(writer, value, type, options);
public static T ReadOrDeserialize<T>(this JsonConverter<T> converter, ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> converter != null ? converter.Read(ref reader, typeToConvert, options) : (T)JsonSerializer.Deserialize(ref reader, typeToConvert, options);
public static void ReadAndAssert(this ref Utf8JsonReader reader)
throw new JsonException();
private static async Task<MarsWheatherRootObject> GetMarsWheatherRootObject(string uri, HttpClient httpClient)
using var httpResponse = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
httpResponse.EnsureSuccessStatusCode();
var stream = await httpResponse.Content.ReadAsStreamAsync();
var root = await System.Text.Json.JsonSerializer.DeserializeAsync<MarsWheatherRootObject>(
new System.Text.Json.JsonSerializerOptions
PropertyNameCaseInsensitive = true
public static async Task Test()
var client = new HttpClient();
var url = @"https://api.nasa.gov/insight_weather/?api_key=DEMO_KEY&feedtype=json&ver=1.0";
var items = await GetMarsWheatherRootObject(url, client);
var newJson = JsonSerializer.Serialize(items, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine("Deserialized and re-serialized {0}:", "MarsWheatherRootObject");
Console.WriteLine(newJson);
public static async Task Main(string[] args)
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Assembly.GetName().Name, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];