首页 > 解决方案 > System.Text.Json - 根据字段属性有条件地使用自定义 JsonConverter

问题描述

我有一个自定义属性[Foo] 实现如下:

public class FooAttribute
  : Attribute
{
}

现在我想使用System.Text.Json.JsonSerializer进入具有该属性的每个字段,以操作如何序列化和反序列化。

例如,如果我有以下课程

class SampleInt
{
    [Foo] 
    public int Number { get; init; }

    public int StandardNumber { get; init; }

    public string Text { get; init; }
}

当我序列化此类的实例时,我希望自定义int JsonConverter仅适用于该字段。

public class IntJsonConverter
    : JsonConverter<int>
{
    public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // do whatever before reading if the text starts with "potato". But this should be triggered only if destination type has the Foo attribute. How?
        return reader.GetInt32();
    }

    public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options)
    {
        writer.WriteStringValue("potato" + value.ToString());
    }
}

以便序列化

var sample =
  new SampleInt
  {
    Number = 123,
    StandardNumber = 456
    Text = "bar"
};

像这样

var serializeOptions = new JsonSerializerOptions();
var serializeOptions.Converters.Add(new IntJsonConverter());
var resultJson = JsonSerializer.Serialize(sample, serializeOptions);

以下json的结果

{
  "number": "potato123",
  "standardNumber": 456,
  "text": "bar"
}

而不是在

{
  "number": "potato123",
  "standardNumber": "potato456",
  "text": "bar"
}

以类似的方式,我希望反序列化是有条件的,并且仅在目标字段具有[Foo]属性时才使用自定义转换器。

使用Newtonsoft,这可以使用合同解析器和CreateProperties像这样的覆盖方法。

public class SerializationContractResolver
    : DefaultContractResolver
{
    private readonly ICryptoTransform _encryptor;
    private readonly FieldEncryptionDecryption _fieldEncryptionDecryption;

    public SerializationContractResolver(
        ICryptoTransform encryptor,
        FieldEncryptionDecryption fieldEncryptionDecryption)
    {
        _encryptor = encryptor;
        _fieldEncryptionDecryption = fieldEncryptionDecryption;
        NamingStrategy = new CamelCaseNamingStrategy();
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var properties = base.CreateProperties(type, memberSerialization);
        foreach (var jsonProperty in properties)
        {
            var hasAttribute = HasAttribute(type, jsonProperty);
            if (hasAttribute)
            {
                var serializationJsonConverter = new MyJsonConverter();
                jsonProperty.Converter = serializationJsonConverter;
            }
        }
        return properties;
    }
    
    private bool HasAttribute(Type type, JsonProperty jsonProperty)
    {
        var propertyInfo = type.GetProperty(jsonProperty.UnderlyingName);
        if (propertyInfo is null)
        {
            return false;
        }
        var hasAttribute =
            propertyInfo.CustomAttributes
                .Any(x => x.AttributeType == typeof(FooAttribute));
        var propertyType = propertyInfo.PropertyType;
        var isSimpleValue = propertyType.IsValueType || propertyType == typeof(string);
        var isSupportedField = isSimpleValue && hasPersonalDataAttribute;
        return isSupportedField;
    }
}

但我不想使用 Newtonsoft。我想使用新的 dotnetSystem.Text.Json序列化程序。是否可以以类似的粒度方式使用它?

标签: c#json.netserializationsystem.text.json

解决方案


推荐阅读