Добавление TypeDiscriminator постоянно с FastEndpoints и сериализатором System.Text.Json

Вопрос или проблема

Я хочу, чтобы System.Text.Json всегда добавлял TypeDiscriminator

Я использую FastEndpoints для создания API, который использует System.Text.Json для сериализации данных.

Моя модель данных выглядит примерно так:

[JsonDerivedType(typeof(Type1), typeDiscriminator: "type1")]
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
abstract record MyBase(Guid Id);

record Type1(Guid Id, string MyProp) : MyBase(Id);

Когда я возвращаю List<MyBase>, сериализатор добавляет дискриминатор типа в результирующий JSON:

[
  {
    "type": "type1",
    "id": "1234567890",
    "myProp": "fu"
  } 
]

Но когда я возвращаю один MyBase, сериализатор пропускает дискриминатор типа:

{
  "id": "1234567890",
  "myProp": "fu"
} 

Как сделать так, чтобы в этом случае также добавлялся дискриминатор типа?

ПРАВКА
Под возвратом я имею в виду, когда вызывается SendOkAsync 😉

Ответ или решение

Чтобы заставить сериализатор System.Text.Json всегда добавлять свойство TypeDiscriminator, даже когда вы возвращаете один объект MyBase, вам нужно настроить кастомный конвертер. Это позволит вам контролировать процесс сериализации и гарантировать, что discriminator будет добавляться независимо от того, возвращается ли список или одиночный элемент.

Вот шаги, которые вам нужно выполнить:

  1. Создайте пользовательский конвертер: Вам понадобится написать специальный конвертер для вашего базового типа, который будет добавлять свойство type при сериализации.
using System;
using System.Text.Json;
using System.Text.Json.Serialization;

public class MyBaseConverter : JsonConverter<MyBase>
{
    public override MyBase Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // Логика чтения объекта из JSON.
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, MyBase value, JsonSerializerOptions options)
    {
        // Сначала сериализуем базовый объект
        var type = value.GetType();
        JsonSerializer.Serialize(writer, value, type, options);

        // Затем добавляем discriminator
        writer.WriteStartObject();
        writer.WriteString("type", type == typeof(Type1) ? "type1" : "unknown"); 
        writer.WriteEndObject();
    }
}
  1. Зарегистрируйте конвертер: Не забудьте зарегистрировать ваш конвертер в настройках сериализации, чтобы он использовался при сериализации объектов MyBase.
var options = new JsonSerializerOptions
{
    Converters = { new MyBaseConverter() },
    WriteIndented = true
};
  1. Используйте настроенный JsonSerializerOptions: Когда вы будете вызывать SendOkAsync, убедитесь, что используете настройки, которые вы создали.
await SendOkAsync(result, options: options);

Теперь, при вызове SendOkAsync с одиночным объектом MyBase, сериализатор должен добавлять свойство type, как и в случае с массивом.

Пример

Теперь, если вы будете возвращать объект типа Type1, результат будет выглядеть следующим образом:

{
  "type": "type1",
  "id": "1234567890",
  "myProp": "fu"
}

Заключение

Таким образом, добавление собственного конвертера для обработки MyBase позволяет вам обеспечить согласованность в сериализации объектов, гарантируя, что свойства типа будут всегда добавлены в JSON, независимо от структуры вывода (список или один объект).

Оцените материал
Добавить комментарий

Капча загружается...