如何添加自定义类型转换进行配置

问题描述 投票:0回答:1

我有一个用于配置的 toml 文件,其中几个部分包含我希望自动解析的 Crontab 表达式,而不是将其捕获为字符串然后解析它。

public record TestConfig(NCrontab.CrontabSchedule Schedule);

_builder.ConfigureAppConfiguration(options =>
{
    options.AddTomlFile("Config.toml");
    options.AddTomlFile("Config.Develop.toml");
});

_builder.ConfigureServices((ctx, services) =>
{
    var test = ctx.Configuration.GetSection(nameof(TestConfig)).Get<TestConfig>() ?? throw new Exception();
}

我尝试过使用自定义

TypeConverter
但它似乎无法选择预期类型,因此所有字符串值都会通过此转换器,因此不是 crontab 的值只会转换为
null

public class CronTabConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
    {
        return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
    }

    public override object? ConvertFrom(ITypeDescriptorContext? context, System.Globalization.CultureInfo? culture, object value)
    {
        if (value is null)
        {
            return null;
        }

        if (value is string strValue)
        {
            return CrontabSchedule.TryParse(strValue);
        }

        return base.ConvertFrom(context, culture, value);
    }

    public static void RegisterTypeConverter()
    {
        TypeDescriptor.AddAttributes(typeof(string), new TypeConverterAttribute(typeof(CronTabConverter)));
    }
}

我可以看到这可能通过 JsonConverters 实现,但我不知道如何为

AddJsonFile
注册自定义转换器。

如果可以的话,我不反对将配置文件切换为 Json。

c# json .net configuration toml
1个回答
0
投票

您的问题与 cron 无关,因此没有必要涉及此问题。与配置相同的故事。您的问题是自定义 JSON 序列化,这里重要的是提及您使用哪一个。

这是我的序列化器工厂,例如:

public static class TextOptionsFactory
{
    // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-7-0
    public static void CustomizeJsonOptions(JsonSerializerOptions options)
    {
        // https://github.com/dotnet/runtime/issues/70352
        options.IncludeFields = true;
        options.ReferenceHandler = ReferenceHandler.IgnoreCycles;
        options.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
        options.PropertyNamingPolicy = null; //JsonNamingPolicy.CamelCase;

        options.Converters.Add(new OptionConverterFactory());
        options.Converters.Add(new ResultConverterFactory());
        options.Converters.Add(new JsonStringEnumConverter());
        options.Converters.Add(new LanguageIdentifierConverter());
        options.Converters.Add(new WordIdentifierConverter());
        options.Converters.Add(new TranslationIdentifierConverter());
        options.Converters.Add(new CodeConverter());
        options.Converters.Add(new LocalIdConverter());
    }

    public static JsonSerializerOptions DisableRequiredConstraint(this JsonSerializerOptions options)
    {
        // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/required-properties
        options.TypeInfoResolver = new DefaultJsonTypeInfoResolver
        {
            Modifiers =
            {
                static typeInfo =>
                {
                    if (typeInfo.Kind != JsonTypeInfoKind.Object)
                        return;

                    foreach (JsonPropertyInfo propertyInfo in typeInfo.Properties)
                    {
                        // Strip IsRequired constraint from every property.
                        propertyInfo.IsRequired = false;
                    }
                }
            }
        };

        return options;
    }

    public static JsonSerializerOptions BuildJsonOptions(bool compact)
    {
        var options = new JsonSerializerOptions
        {
            WriteIndented = !compact,
        };

        CustomizeJsonOptions(options);

        return options;
    }
}

转换器之一:

public sealed class WordIdentifierConverter : JsonConverter<WordId>
{
    public override WordId Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) =>
        new WordId(reader.GetInt32());

    public override void Write(
        Utf8JsonWriter writer,
        WordId wordId,
        JsonSerializerOptions options) =>
        writer.WriteNumberValue(wordId.Id);

    public override void WriteAsPropertyName(
        Utf8JsonWriter writer,
        WordId wordId,
        JsonSerializerOptions options) =>
        writer.WritePropertyName(wordId.Id.ToString());

    public override WordId ReadAsPropertyName(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) =>
        new WordId(reader.GetInt32());
}

并进行设置,具体取决于您何时需要 - 我发现您需要它来读取文件,我还没有准备好使用示例,但您应该找到与这里类似的内容:

var mvc_builder = builder.Services.AddControllers();
mvc_builder.AddJsonOptions(json =>   TextOptionsFactory.CustomizeJsonOptions(json.JsonSerializerOptions));
© www.soinside.com 2019 - 2024. All rights reserved.