从启动时全局设置的JsonStringEnumConverter中排除模型的枚举属性? [英] Exclude an enum property of a Model from using the JsonStringEnumConverter which is globally set at the Startup?

查看:100
本文介绍了从启动时全局设置的JsonStringEnumConverter中排除模型的枚举属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用最新的.NET Core 3.1.1和 System.Text.Json (以前使用的是 Newtonsoft.Json )开发ASP.NET Core应用程序.如Microsoft

I am developing the ASP.NET Core Application using the latest .NET Core 3.1.1 and System.Text.Json which was previously using the Newtonsoft.Json. As recommended in the Microsoft Migration guide I have done the changes. Also, as most of my enums need to be serialized as String I have configured my Startup.cs ConfigureServices to use the JsonStringEnumConverter globally.

public void ConfigureServices(IServiceCollection services)
{
    // lines omitted for brevity

    services.AddControllers()
                .AddJsonOptions(options =>
                    {
                        options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
                        options.JsonSerializerOptions.IgnoreNullValues = true;
                        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
                    });
}

但是最近,在发布之后,我们意识到通过我们的API在json中只给出了几个枚举作为数字.由于这些API是在外部使用的,因此将数字更改为字符串可能是一项昂贵的工作.

But recently, after the release we realized that only a few enums are given out as numerals in json through our API. As these APIs are consumed externally, changing the numerals to strings might be a costly stuff.

那么,有没有办法忽略某些枚举属性的通用性,例如使用 [JsonIgnore] 属性进行修饰?

So, is there a way to ignore the universal for some enum properties like the decoration with the [JsonIgnore] attribute?

推荐答案

JsonConverterFactory .它制造一个特定的

JsonStringEnumConverter is actually a subclass of JsonConverterFactory. It manufactures a specific JsonConverterEnum for each concrete enum type encountered during serialization that, in turn, serializes that specific enum type as a string.

如果您不想将某些特定的 enum type 序列化为字符串,则可以使用

If you don't want some specific enum type to be serialized as a string, you can use the decorator pattern and create your own converter factory that decorates a JsonStringEnumConverter but prevents that enum type from being converted as follows:

public class OptOutJsonConverterFactory : JsonConverterFactoryDecorator
{
    readonly HashSet<Type> optOutTypes;

    public OptOutJsonConverterFactory(JsonConverterFactory innerFactory, params Type [] optOutTypes) : base(innerFactory) => this.optOutTypes = optOutTypes.ToHashSet();

    public override bool CanConvert(Type typeToConvert) => base.CanConvert(typeToConvert) && !optOutTypes.Contains(typeToConvert);
}

public class JsonConverterFactoryDecorator : JsonConverterFactory
{
    readonly JsonConverterFactory innerFactory;

    public JsonConverterFactoryDecorator(JsonConverterFactory innerFactory)
    {
        if (innerFactory == null)
            throw new ArgumentNullException(nameof(innerFactory));
        this.innerFactory = innerFactory;
    }

    public override bool CanConvert(Type typeToConvert) => innerFactory.CanConvert(typeToConvert);

    public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => innerFactory.CreateConverter(typeToConvert, options);
}

然后在以下选项中使用它:

Then use it in options as follows:

options.Converters.Add(new OptOutJsonConverterFactory(new JsonStringEnumConverter(), 
                                                      // Add here all enum types to serialize as integers:
                                                      typeof(SomeEnumNotToSerializeAsAString)
                                                      //, ...
                                                     ));

注意:

  • If maintaining a list of enum types to serialize as integers is inconvenient, you could mark the enum types to be serialized as integers with some custom attribute, then exclude types marked with that attribute from within CanConvert(CanConvert(Type typeToConvert).

装饰器模式是必需的,因为 JsonStringEnumConverter 是密封的.

The decorator pattern is required because JsonStringEnumConverter is sealed.

模型小提琴#1 此处.

或者,如果您不希望将某些特定的 enum 属性序列化为字符串,则可以使用

Alternatively, if you don't want some specific enum property to be serialized as a string, you can apply a converter to the property using JsonConverterAttribute that ignores the incoming JsonSerializerOptions and generates a default serialization instead:

/// <summary>
/// Apply this converter to a property to force the property to be serialized with default options.  
/// This converter can ONLY be applied to a property; setting it in options or on a type may cause a stack overflow exception!
/// </summary>
/// <typeparam name="T">the property's declared return type</typeparam>
public class SerializePropertyAsDefaultConverter<T> : JsonConverter<T>
{
    public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return JsonSerializer.Deserialize<T>(ref reader); // Ignore the incoming options!
    }

    public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
    {
        JsonSerializer.Serialize(writer, value); // Ignore the incoming options!
    } 
}

并将其应用于您的模型,如下所示:

And apply it to your model as follows:

public class Model
{
    public StringEnum StringEnum { get; set; }

    [JsonConverter(typeof(SerializePropertyAsDefaultConverter<SomeEnumNotToSerializeAsAString>))]
    public SomeEnumNotToSerializeAsAString SomeEnumNotToSerializeAsAString { get; set; }
}

注意:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆