System.Text.Json Глобальная сериализация нулевых строк в пустые строки

При переносе кода с newtonsoft json на system.text.json

Мне нужно, чтобы все строки, допускающие значение NULL, отображались как пустая строка.

Я написал следующий преобразователь, но все значения нулевой строки по-прежнему отображаются как нулевые.

А для значений нулевой строки метод Write не вызывается. Точка останова никогда не достигается.

    public class EmptyStringConverter : JsonConverter<string>
    {
        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            => Convert.ToString(reader.GetString(), CultureInfo.CurrentCulture);

        public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.WriteStringValue(value ?? "");
        }
    }

Код запуска

    services.AddControllers()
        .AddJsonOptions(option =>
        {
            option.JsonSerializerOptions.Converters.Add(new EmptyStringConverter());
        });

Пример консоли

    class Program
    {
        static void Main(string[] args)
        {
            var jsonSerializerOptions = new JsonSerializerOptions();
            jsonSerializerOptions.Converters.Add(new EmptyStringConverter());
            var json = JsonSerializer.Serialize(new Model() { FirstName = null }, jsonSerializerOptions);
        }
    }

    public class EmptyStringConverter : JsonConverter<string>
    {
        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
            => Convert.ToString(reader.GetString(), CultureInfo.CurrentCulture);

        public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
        {
            if (writer == null)
                throw new ArgumentNullException(nameof(writer));
            writer.WriteStringValue(value ?? "");
        }
    }

    public class Model
    {
        public string FirstName { get; set; }
    }

3 ответа

Решение

В .NET 5.0 это можно сделать, переопределивJsonConverter<T>.HandleNull и возвращение true:

      public class EmptyStringConverter : JsonConverter<string>
{
    public override bool HandleNull => true;
    
    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        => reader.TokenType == JsonTokenType.Null ? "" : reader.GetString();

    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) =>
        writer.WriteStringValue(value ?? "");
}

Дополнительные сведения см. В разделе Обработка нулевых значений.

Демо скрипка здесь .

В .NET Core 3.x это не реализовано. Из Обработка нулевых значений в .NET Core 3.x:

Обрабатывать нулевые значения

По умолчанию сериализатор обрабатывает нулевые значения следующим образом:

  • Для справочных типов и Nullable<T> типы:

    • Он не передает значение null пользовательским конвертерам при сериализации.
    • Он не передает JsonTokenType.Null настраиваемым конвертерам при десериализации.
    • Он возвращает нулевой экземпляр при десериализации.
    • Он записывает null непосредственно в писатель при сериализации.
  • Для типов значений, не допускающих значения NULL:

    • Он передает JsonTokenType.Null настраиваемым конвертерам при десериализации. (Если пользовательский преобразователь недоступен, внутренний преобразователь для типа выдает исключение JsonException.)

Такое поведение обработки нулевого значения в первую очередь предназначено для оптимизации производительности за счет пропуска дополнительного вызова преобразователя. Кроме того, он позволяет избежать принуждения преобразователей для типов, допускающих значение NULL, для проверки наличия NULL в начале каждого переопределения методов Read и Write.

Попытайся

/// <summary>
/// Convert empty to null when read data json
/// </summary>
public class EmptyStringToNullConverter : JsonConverter<string>
{
    /// <summary>
    /// Override CanConvert method of JsonConverter
    /// This instance only convert the string type.
    /// </summary>
    /// <returns></returns>
    public override bool CanConvert(Type typeToConvert)
    {
        return typeToConvert == typeof(string);
    }

    /// <summary>
    /// Override ReadJson method of JsonConverter
    /// Convert string null to empty
    /// </summary>
    /// <returns></returns>
    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string value = (string)reader.GetString();
        return value ?? String.Empty;
    }

    /// <summary>
    /// Override WriteJson method of JsonConverter
    /// </summary>
    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
    {
        throw new NotImplementedException("Unnecessary");
    }
}

@ Халил, не могли бы вы дать образец кода? В моем сообществе VS2017 вызывается метод записи.

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var emptyStringConverter = new EmptyStringConverter();
            emptyStringConverter.Write(null, null, null);
        }
    }
}

EmptyStringConverter класс:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ConsoleApp1
{
    public class EmptyStringConverter : JsonConverter<string>
    {
        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            throw new NotImplementedException();
        }

        public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
        {
            ;
        }
    }
}
Другие вопросы по тегам