c# - Asp.Net Core 3.1 Appsettings 不尊重 JsonConverter

标签 c# asp.net-core .net-core application-settings jsonconverter

在 asp.net core 3.1 中,使用新的 System.Text.Json,我试图在 appsettings 部分使用自定义 JsonConverter。手动序列化/反序列化尊重转换器就好了,但通过选项模式从 appSettings 读取则不行。这是我所拥有的:
Json 转换器。为简单起见,这只是将字符串值转换为大写:

    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 类,在字符串属性上声明转换器:
    public class MyOptions
    {
        public const string Name = "MyOptions";
        [JsonConverter(typeof(UpperConverter))]
        public string MyString { get; set; }
    }
Startup.cs 更改以准备一切:
       public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews()
                .AddJsonOptions(options =>
                {
                    options.JsonSerializerOptions.Converters.Add(new UpperConverter());
                });

            services.Configure<MyOptions>(Configuration.GetSection(MyOptions.Name));
        }
当我注入(inject) IOptions<MyOptions>进入 HomeController,它读取一个小写的值。如果我手动执行 JsonSerializer.Deserialize<MyOptions>("{\"MyString\":\"lowercase_manual\"}") ,我得到一个大写字符串。即使我删除了 JsonSerializerOptions 的启动声明。
有谁知道如何让 appsettings/options 模式尊重 JsonConverter?我必须在其他地方声明 JsonSerializerOptions 吗?谢谢。

最佳答案

重要的是要了解 options pattern实现为两个独立的步骤:从配置源读取数据,然后将该数据绑定(bind)到强类型对象。
读取步骤由各种配置提供程序实现,其中只有一个是 JSON。您可能期望 JSON 提供程序会尊重您的 JsonConverter ,但此步骤仅将其配置数据转换为下一步可以接受的通用格式。
那么,绑定(bind)步骤似乎是关心 JsonConverter 的地方。 .但是这一步有意完全不知道任何特定的配置提供者,因为它只是从提供者 接收通用格式的数据。它故意对一无所知.因此,它不会关心特定于 JSON 的转换器。
然而,它会关心更多的通用转换器来处理其通用数据,幸运的是.NET 已经为此内置了基础设施:type converters .这些几乎从一开始就在 .NET 中,虽然它们很旧,但它们非常简单、可维护,并且确实非常适合这种特定场景。
如何实现类型转换器的完整示例超出了此答案的范围,但要点是您从 TypeConverter 派生。 ,覆盖适当的方法,并用 TypeConverterAttribute 装饰要转换的类指向您的TypeConverter执行。那么它应该都是 Just Work™。

您提供的示例需要注意的是,您实际上并没有尝试 转换 任何东西,你都在尝试 变换 一个字符串,显然是一个 TypeConverter不会被调用,因为来自配置提供程序的源值是一个字符串,而您的选项类上的目标类型也是一个字符串。
您可以做的是创建一个新类,该类包装一个字符串以将其强制为大写:

public class UppercaseString
{
    public string Value { get; }

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

    public static implicit operator string(UppercaseString upper)
        => upper.Value;
}
然后更改您的选项类以使用该包装器:
public class MyOptions
{
    public const string Name = "MyOptions";

    public UppercaseString MyString { get; set; }
}
最后,实现 TypeConverterstring 转换至UppercaseString .
注意 implicit operator string 的定义- 这允许您使用 UppercaseString任何地方的标准string是预期的,因此您不必更改引用 MyOptions.MyString 的代码至MyOptions.MyString.Value .

关于c# - Asp.Net Core 3.1 Appsettings 不尊重 JsonConverter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62820147/

相关文章:

c# - 使用用户名和密码 .netcore 2 的 Swagger Auth

c# - 如何测试 Entity Framework 中随时间发生的查询数量?

c# - 泛型方法可能会抛出异常

c# - 如何按名称查找 bindingSource?

c# - 在asp net core 3.0中返回文件会泄漏内存

c# - Azure 应用服务中的 IWebHostEnvironment ContentRootPath 与本地不同

c# - .net Core Quartz 依赖注入(inject)

c# - 使用 System.IO.Directory.CreateDirectory() 时出现 FileNotFoundException

c# - 删除 Split View中的单选按钮图标 Windows 通用应用程序

azure - 无法使用Azure Function App使用内存缓存