Skip to content

Instantly share code, notes, and snippets.

@egil
Last active November 13, 2020 11:35
Show Gist options
  • Save egil/ac0974eeb2655cfe32e7fbecc08cbf3a to your computer and use it in GitHub Desktop.
Save egil/ac0974eeb2655cfe32e7fbecc08cbf3a to your computer and use it in GitHub Desktop.
Draft for EntityCosmosJsonConverter that avoids poluting domain objects with Cosmos specific properties
using System;
public abstract class Entity
{
public Guid Id { get; set; }
}
using System;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
public class EntityCosmosJsonConverter : JsonConverter<Entity>
{
private readonly JsonSerializerOptions converterOptions;
public override bool CanConvert(Type typeToConvert)
=> typeof(Entity).IsAssignableFrom(typeToConvert);
public EntityCosmosJsonConverter(JsonSerializerOptions options)
{
converterOptions = CopyOptionsExceptSelf(options);
}
public override Entity Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
var result = JsonSerializer.Deserialize(ref reader, typeToConvert, converterOptions) as Entity;
return result ?? throw new JsonException("TAAAADA");
}
public override void Write(Utf8JsonWriter writer, Entity entity, JsonSerializerOptions options)
{
var entityType = entity.GetType();
writer.WriteStartObject();
// Add cosmos specific fields
writer.WriteString("id", entity.Id);
writer.WriteString("pk", entityType.Name);
foreach (var propertyInfo in entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
if (propertyInfo.Name.Equals("id", StringComparison.OrdinalIgnoreCase))
continue;
if (!propertyInfo.CanWrite && options.IgnoreReadOnlyProperties)
continue;
var value = propertyInfo.GetValue(entity);
if (value is { } || !options.IgnoreNullValues)
{
var propertyName = options.PropertyNamingPolicy?.ConvertName(propertyInfo.Name) ?? propertyInfo.Name;
writer.WritePropertyName(propertyName);
JsonSerializer.Serialize(writer, value, propertyInfo.PropertyType, converterOptions);
}
}
writer.WriteEndObject();
}
private static JsonSerializerOptions CopyOptionsExceptSelf(JsonSerializerOptions options)
{
var result = new JsonSerializerOptions
{
AllowTrailingCommas = options.AllowTrailingCommas,
DefaultBufferSize = options.DefaultBufferSize,
DictionaryKeyPolicy = options.DictionaryKeyPolicy,
Encoder = options.Encoder,
IgnoreNullValues = options.IgnoreNullValues,
IgnoreReadOnlyProperties = options.IgnoreReadOnlyProperties,
MaxDepth = options.MaxDepth,
PropertyNameCaseInsensitive = options.PropertyNameCaseInsensitive,
PropertyNamingPolicy = options.PropertyNamingPolicy,
ReadCommentHandling = options.ReadCommentHandling,
WriteIndented = options.WriteIndented
};
// Copy options but skip the adding this converter.
foreach (var converter in options.Converters)
{
if (converter is EntityCosmosJsonConverter)
continue;
result.Converters.Add(converter);
}
return result;
}
}
{
"id": "3353613d-a173-4e25-b99c-092f35145d1d",
"pk": "Todo",
"name": "Remove Cosmos from entities",
"_rid": "EFNFAIGlGTwYAAAAAAAAAA==",
"_self": "dbs/EFNFAA==/colls/EFNFAIGlGTw=/docs/EFNFAIGlGTwYAAAAAAAAAA==/",
"_etag": "\"00000000-0000-0000-b8ed-658a050c01d6\"",
"_attachments": "attachments/",
"_ts": 1605183280
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment