Asp.Net Core 3.1 Appsettings不尊重JsonConverter [英] Asp.Net Core 3.1 Appsettings not respecting JsonConverter

查看:79
本文介绍了Asp.Net Core 3.1 Appsettings不尊重JsonConverter的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在asp.net core 3.1中,使用新的System.Text.Json,我试图在appsettings部分使用自定义JsonConverter.手动序列化/反序列化可以很好地支持转换器,但是通过选项"模式从appSettings中读取则不可行.这就是我所拥有的:

In asp.net core 3.1, using the new System.Text.Json, I am trying to use a custom JsonConverter on an appsettings section. Manually serializing/deserializing respects the converter just fine, but reading from appSettings via Options pattern does not. Here's what I have:

JsonConverter.为简单起见,此代码只是将字符串值转换为大写:

The JsonConverter. For simplicity, this one just converts a string value to uppercase:

    public class UpperConverter : JsonConverter<string>
    {
        public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
            reader.GetString().ToUpper();

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

appsettings类,在字符串属性上声明转换器:

The appsettings class, declaring the converter on a string property:

    public class MyOptions
    {
        public const string Name = "MyOptions";
        [JsonConverter(typeof(UpperConverter))]
        public string MyString { get; set; }
    }

Startup.cs进行更改以准备一切:

The Startup.cs changes to prepare everything:

       public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews()
                .AddJsonOptions(options =>
                {
                    options.JsonSerializerOptions.Converters.Add(new UpperConverter());
                });

            services.Configure<MyOptions>(Configuration.GetSection(MyOptions.Name));
        }

当我将 IOptions< MyOptions> 注入HomeController时,它将读取一个小写的值.如果我手动执行 JsonSerializer.Deserialize< MyOptions>("{\" MyString \:\" lowercase_manual \}}"),则会得到一个大写的字符串.即使删除了JsonSerializerOptions的启动声明.

When I inject an IOptions<MyOptions> into the HomeController, it reads a lowercase value. If I manually do JsonSerializer.Deserialize<MyOptions>("{\"MyString\":\"lowercase_manual\"}"), I get an uppercase string. Even when I remove Startup declarations of JsonSerializerOptions.

有人知道如何获得appsettings/options模式以尊重JsonConverter吗?我是否需要在其他地方声明JsonSerializerOptions?谢谢.

Does anyone know how to get the appsettings / options pattern to respect the JsonConverter? Do I have to declare the JsonSerializerOptions somewhere else? Thanks.

推荐答案

重要的是要了解

It's important to understand that the options pattern is implemented as two separate steps: reading data from a configuration source, then binding that data to strongly-typed objects.

读取步骤由各种配置提供程序实现,其中只有一个是JSON.您可能希望JSON提供程序会尊重您的 JsonConverter ,但是此步骤仅将其配置数据转换为下一步可以接受的通用格式的操作最少.

The read step is implemented by various configuration providers, only one of which is JSON. You might expect that the JSON provider would respect your JsonConverter, but this step only performs minimal transformation of its configuration data into a generic format that the next step can accept.

然后,绑定步骤似乎是关心 JsonConverter 的地方.但是此步骤有意完全与任何特定的配置提供程序无关,因为它仅从提供程序有意不了解的通用格式接收数据.因此,它不会关心JSON特定的转换器.

The binding step, then, would seem to be the place that would care about JsonConverter. But this step is intentionally completely agnostic of any specific configuration provider, because it simply receives data in a generic format from the providers of which it purposefully knows nothing about. Therefore, it won't care about a JSON-specific converter.

但是,它将关注更多的通用转换器来处理其通用数据,幸运的是.NET已经内置了用于此的基础结构:

It will, however, care about more generic converters to handle its generic data, and fortunately .NET already has infrastructure for this built in: type converters. These have been in .NET since almost the beginning, and while they're old they're perfectly simple, serviceable, and indeed ideal for this specific scenario.

关于如何实现类型转换器的完整示例超出了此答案的范围,但是要点是,您必须从 TypeConverter 派生,重写适当的方法,并装饰想要的类.用 TypeConverterAttribute 指向后进行转换到您的 TypeConverter 实现中.然后就应该全部使用Just Work™.

A full example of how to implement a type converter is out of scope for this answer, but the essentials are that you derive from TypeConverter, override the appropriate methods, and decorate the class you want to be converted with a TypeConverterAttribute pointing back to your TypeConverter implementation. Then it should all Just Work™.

您提供的示例的警告是,您实际上并没有在尝试转换,而是在尝试转换一个字符串,并且显然 TypeConverter 不会被调用,因为来自配置提供程序的源值是一个字符串,而选项类上的目标类型也是一个字符串.

The caveat with the example you've provided is that you aren't actually trying to convert anything, you're trying to transform a string, and obviously a TypeConverter won't be invoked since the source value from the configuration providers is a string, while the destination type on your options class is also a string.

您可以做的是创建一个新类,该类包装一个字符串以将其强制为大写:

What you can do instead is create a new class that wraps a string to force it to uppercase:

public class UppercaseString
{
    public string Value { get; }

    public UppercaseString(string str)
    {
        Value = str.ToUpper();
    }

    public static implicit operator string(UppercaseString upper)
        => upper.Value;
}

然后将您的选项类更改为使用 UppercaseString :

then change your options class to use UppercaseString:

public class MyOptions
{
    public const string Name = "MyOptions";

    public UppercaseString MyString { get; set; }
}

,然后实现一个 TypeConverter ,该类型将从 string 转换为 UppercaseString .

and then implement a TypeConverter that converts from string to UppercaseString.

请注意隐式运算符字符串的定义-这允许您在需要标准 string 的任何地方使用 UppercaseString ,这样您就不必不必将引用 MyOptions.MyString 的代码更改为 MyOptions.MyString.Value .

Note the definition of implicit operator string - this allows you to use an UppercaseString anywhere a standard string is expected, so that you don't have to change your code that references MyOptions.MyString to MyOptions.MyString.Value.

这篇关于Asp.Net Core 3.1 Appsettings不尊重JsonConverter的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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