如何使用IOptions等来验证.net核心配置中的一系列项目



我很难找到一种方法来验证。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(数据注释和转换错误都会导致抛出异常,例如对于

{
"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中只得到一个项目。内部人(第一个)和我似乎找不到一种方式让它以某种方式"参与"。在验证-或绑定失败的"abc"通过异常报告。

任何想法?

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

您可以实现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的文档。