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

查看:47
本文介绍了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 注入 HomeController 时,它读取一个小写值.如果我手动执行 JsonSerializer.Deserialize("{"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 已经为此内置了基础设施:类型转换器.这些几乎从一开始就在 .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;
}

然后更改您的选项类以使用该包装器:

then change your options class to use that wrapper:

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

    public UppercaseString MyString { get; set; }
}

最后,实现一个 TypeConverterstring 转换为 UppercaseString.

and finally, 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天全站免登陆