This repository has been archived on 2022-08-05. You can view files and clone it, but cannot push or open issues or pull requests.
CC-Functions/AspNet/DictionaryGuidConverter.cs

138 lines
4.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace CC_Functions.AspNet
{
/// <summary>
/// Provides serializing dictionary with Guid keys
/// </summary>
public class DictionaryGuidConverter : JsonConverterFactory
{
/// <inheritdoc />
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
if (typeToConvert.GetGenericTypeDefinition() != typeof(Dictionary<,>))
{
return false;
}
return typeToConvert.GetGenericArguments()[0] == typeof(Guid);
}
/// <inheritdoc />
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
Type valueType = typeToConvert.GetGenericArguments()[1];
JsonConverter converter = (JsonConverter)Activator.CreateInstance(
typeof(DictionaryGuidConverterInner<>).MakeGenericType(valueType),
BindingFlags.Instance | BindingFlags.Public,
null,
new object[] { options },
null);
return converter;
}
private class DictionaryGuidConverterInner<TValue> : JsonConverter<Dictionary<Guid, TValue>>
{
private readonly JsonConverter<TValue> _valueConverter;
private Type _valueType;
public DictionaryGuidConverterInner(JsonSerializerOptions options)
{
// For performance, use the existing converter if available.
_valueConverter = (JsonConverter<TValue>)options
.GetConverter(typeof(TValue));
// Cache the key and value types.
_valueType = typeof(TValue);
}
public override Dictionary<Guid, TValue> Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException();
}
Dictionary<Guid, TValue> dictionary = new Dictionary<Guid, TValue>();
while (reader.Read())
{
if (reader.TokenType == JsonTokenType.EndObject)
{
return dictionary;
}
// Get the key.
if (reader.TokenType != JsonTokenType.PropertyName)
{
throw new JsonException();
}
string propertyName = reader.GetString();
// For performance, parse with ignoreCase:false first.
if (!Guid.TryParse(propertyName, out Guid key))
{
throw new JsonException(
$"Unable to convert \"{propertyName}\" to Guid.");
}
// Get the value.
TValue v;
if (_valueConverter != null)
{
reader.Read();
v = _valueConverter.Read(ref reader, _valueType, options);
}
else
{
v = JsonSerializer.Deserialize<TValue>(ref reader, options);
}
// Add to dictionary.
dictionary.Add(key, v);
}
throw new JsonException();
}
public override void Write(
Utf8JsonWriter writer,
Dictionary<Guid, TValue> dictionary,
JsonSerializerOptions options)
{
writer.WriteStartObject();
foreach (KeyValuePair<Guid, TValue> kvp in dictionary)
{
writer.WritePropertyName(kvp.Key.ToString());
if (_valueConverter != null)
{
_valueConverter.Write(writer, kvp.Value, options);
}
else
{
JsonSerializer.Serialize(writer, kvp.Value, options);
}
}
writer.WriteEndObject();
}
}
}
}