属性 的自定义配置活页夹

Custom Configuration Binder for Property

我在 ASP.NET 核心 1.1 解决方案中使用配置绑定。基本上,我在 ConfigureServices Startup 部分中有一些简单的绑定代码,如下所示:

services.AddSingleton(Configuration.GetSection("SettingsSection").Get<SettingsClass>());

问题是我的 class 作为一个 int 属性 通常绑定到配置文件中的一个 int 值,但可以改为绑定到字符串 "disabled"。在引擎盖下,如果 属性 绑定到字符串 "disabled".

,我希望它获得值 -1

它可能比这更复杂,但为了简洁起见,我进行了简化。

我的问题是:我如何提供自定义 binder/converter 来覆盖 SettingsClass 中特定 属性 的配置绑定,以便在进行字符串转换时它将转换 "disabled" 到 -1,而不是抛出 "disabled" 无法转换为 Int32?

的异常

似乎由于 ConfigurationBinder 使用类型的 TypeDescriptor 来获取转换器,所以我做我想做的事情的唯一方法是实现自定义类型转换器并将其插入到 class 我正在转换为(在本例中为 Int32)。

所以,基本上,在配置发生之前添加:

TypeDescriptor.AddAttributes(typeof(int), new TypeConverterAttribute(typeof(MyCustomIntConverter)));

MyCustomIntConverter 看起来像这样:

public class MyCustomIntConverter  : Int32Converter
{
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value != null && value is string)
        {
            string stringValue = value as string;
            if(stringValue == "disabled")
            {
                return -1;
            }
        }
        return base.ConvertFrom(context, culture, value);
    }
}

似乎有点矫枉过正,因为现在 "disabled" 将在应用程序的任何地方始终将 Int32 转换为 -1。如果有人知道一种侵入性较小的方法,请告诉我。

我最近偶然发现了同样的问题,并提出了稍微不同的解决方案。

我的想法是使用默认绑定机制。在我的例子中,我想获得 HashSet 的新实例,其值存储在我的数据库中的 proper array format 中。我创建了一个 class 我将我的配置绑定到一个 private 属性 命名为我的配置和一个 public 属性,它使用 private 一个给我创建一个 HashSet 的实例。它看起来有点像这样:

// settings.json
{
    option: {
        ids:[1,2,3],
    }
}

class

public class Options
{
    public HashSet<int> TrueIds
    {
        get
        {
            return RestrictedCategoryIds?.ToHashSet();
        }
    }

    private int[] Ids{ get; set; }
}

然后您可以使用 BindNonPublicProperties 来确保活页夹将填充您的 private 属性.

// Startup.cs
services.Configure<Options>(Configuration, c => c.BindNonPublicProperties = true);

你说在你的情况下这可能不像将 "disabled" 转换为 -1 那么简单,但也许我的想法会启发你以不同的方式解决这个问题。