【问题标题】:How to validate a sequence of items from .NET Core configuration using IOptions etc如何使用 IOptions 等验证 .NET Core 配置中的一系列项目
【发布时间】:2021-12-06 07:41:55
【问题描述】:

我很难找到一种方法来按顺序验证 .NET Core 配置中的项目(已尝试使用 .NET 5 和 3.1)。

说我的设置是这样的:

{
"MyOpt": {
    "IntOpt": 5,
    "StrOpt": "...",
    "Inner": {
        "InnerStr": "...",
        "InnerInt": 7
    },
    "Inners": [
        {
            "InnerStr": "...",
            "InnerInt": 1
        },
        {
            "InnerStr": "...",
            "InnerInt": 2
        }
    ]
}
}


public class Inner
{
    public string InnerStr { get; set; }

    [Range(0, 1000, ErrorMessage = "Value {0} must be between {1} and {2}")]
    public int InnerInt { get; set; }
}

public class MyOpt
{
    [Range(0, 1000, ErrorMessage = "Value {0} must be between {1} and {2}")]
    public int IntOpt { get; set; }
    public string StrOpt { get; set; }
    public IEnumerable<Inner> Inners { get; set; }
}

我在我的 Startup.cs 中这样配置它:

services
  .AddOptions<MyOpt>()
  .Bind(Configuration.GetSection("MyOpt"))
  .ValidateDataAnnotations();

当我尝试从 WebAPI 的控制器中访问它时:

    public HomeController(ILogger<HomeController> logger, IOptions<OptOpt> options)
    {
        var whatever = options.Value.IntOpt;
        _logger = logger;
    }

MyOpt.IntOpt 或 MyOpt.Inner.InnerInt 的验证正确启动(数据注释和转换错误都会导致抛出异常,例如 for

{
"MyOpt": {
    "IntOpt": "abc",
    ...
}

我觉得不错

ArgumentException: abc is not a valid value for Int32. (Parameter 'value').

然而,如果 MyOpt.Inners 项目之一配置错误,它会被静默删除,例如对于

{
"MyOpt": {
    // ...
    "Inners": [
        {
            "InnerStr": "...",
            "InnerInt": 1
        },
        {
            "InnerStr": "...",
            "InnerInt": "abc"
        }
    ]
}
}

我在 MyOpt.Inners 中只得到一个项目(第一个),我似乎无法找到一种方法来以某种方式“参与”验证 - 或者通过报告“abc”的绑定失败一个例外。

有什么想法吗?

【问题讨论】:

    标签: c# .net .net-core configuration .net-standard-2.0


    【解决方案1】:

    默认情况下,验证属性不会进入集合并验证其内容,这就是不调用集合中元素的属性的原因。

    您可以实现IValidatableObject 并触发您集合中项目的验证:

     public class MyOpt : IValidatableObject
        {
            [Range(0, 1000, ErrorMessage = "Value {0} must be between {1} and {2}")]
            public int IntOpt { get; set; }
            public string StrOpt { get; set; }
            public IEnumerable<Inner> Inners { get; set; }
        
            public IEnumerable<ValidationResult> Validate(ValidationContext validationContext){
              var results = new List<ValidationResult>();
              foreach (var item in this.Inners){
              var validationResults = new List<ValidationResult>();
                   if (!Validator.TryValidateObject(item, new ValidationContext(item, validationContextItems), validationResults, true)))
        {
    results.AddRange(validationResults);
    }
    
              }
            }
    
    return result;
        }
    

    注意:代码未经测试,只是一个快速建议,请在IValidatableObjectValidator 上查找文档。

    【讨论】:

    • 好的,谢谢。是的,我尝试了一个变体,使用services.TryAddEnumerable(ServiceDescriptor.Singleton&lt;IValidateOptions&lt;MyOpt&gt;, MyOptValidator&gt;()); - 它有效,但看起来太手动了。我也试过AddOptions&lt;Inner&gt;(),但这似乎也没有用:-(
    猜你喜欢
    • 2019-06-12
    • 1970-01-01
    • 2021-03-16
    • 2019-05-19
    • 1970-01-01
    • 1970-01-01
    • 2021-03-10
    • 2023-04-07
    • 2020-07-20
    相关资源
    最近更新 更多