Mor*_*sen 5 c# validation asp.net-core
在这里,提出了一个问题,即如何验证不可为空的必需类型。
在我的情况下,不希望提供如下使字段为空的解决方案。
[Required]
public int? Data { get; set; }
Run Code Online (Sandbox Code Playgroud)
在请求中省略该字段的情况下,如何更改行为以进行以下失败验证。
[Required]
public int Data { get; set; }
Run Code Online (Sandbox Code Playgroud)
我尝试了一个自定义验证器,但是这些没有原始值的信息,只能看到默认0值。我还尝试了自定义模型绑定程序,但它似乎可以在整个请求模型的级别上运行,而不是在所需的整数字段上运行。我的资料夹实验看起来像这样:
public class RequiredIntBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ModelType != typeof(int))
throw new InvalidOperationException($"{nameof(RequiredIntBinder)} can only be applied to integer properties");
var value = bindingContext.ValueProvider.GetValue(bindingContext.BinderModelName);
if (value == ValueProviderResult.None)
{
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
return new SimpleTypeModelBinder(bindingContext.ModelType).BindModelAsync(bindingContext);
}
}
public class RequiredIntBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(int))
{
return new BinderTypeModelBinder(typeof(RequiredIntBinder));
}
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
并像这样在mvc中注册
options.ModelBinderProviders.Insert(0, new RequiredIntBinderProvider());
Run Code Online (Sandbox Code Playgroud)
但从未使用过模型绑定器。我觉得我可能很近,但无法连接最后一个点。
您无法验证已创建的模型实例,因为不可为 null 的属性始终具有值(无论它是从 json 分配还是默认值)。该解决方案是反序列化过程中已经报告丢失的价值。
创建合约解析器
public class RequiredPropertiesContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
foreach (var contractProperty in contract.Properties)
{
if (contractProperty.PropertyType.IsValueType
&& contractProperty.AttributeProvider.GetAttributes(typeof(RequiredAttribute), inherit: true).Any())
{
contractProperty.Required = Required.Always;
}
}
return contract;
}
}
Run Code Online (Sandbox Code Playgroud)
然后将其分配给SerializerSettings:
services.AddMvc()
.AddJsonOptions(jsonOptions =>
{
jsonOptions.SerializerSettings.ContractResolver = new RequiredPropertiesContractResolver();
});
Run Code Online (Sandbox Code Playgroud)
所述ModelState然后是无效的与非空的属性[Required]属性如果值是从JSON丢失。
JSON 体
var jsonBody = @"{ Data2=123 }"
Run Code Online (Sandbox Code Playgroud)
对模型无效
class Model
{
[Required]
public int Data { get; set; }
public int Data2 { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
请求中的所有内容都只是一个字符串。模型绑定器将请求正文中的键与属性名称进行匹配,然后尝试将它们强制转换为适当的类型。如果该属性未发布或使用空字符串发布,则在尝试转换为 int 时显然会失败。因此,您最终会得到该类型的默认值。在的情况下int这是0,虽然默认值int?是null。
只有在此绑定过程完成后,模型才会被验证。请记住,您正在验证模型而不是帖子正文。没有合理的方法来验证帖子正文,因为同样,它只是一堆键值对字符串。因此,在int需要但未发布的属性的情况下,值为0,这是 int 的完全有效值,并且验证得到满足。在 的情况下int?,值为null,它不是有效的 int,因此验证失败。这就是为什么需要 nullable 的原因,如果你想要求一个不可为 null 的类型有一个值。这是将空值与简单的“默认”值区分开来的唯一方法。
如果您正在使用视图模型,这应该不是问题。您可以绑定到具有必需属性的可空 int,并且如果您的模型状态有效,您将确信它会有一个值,尽管它可以为空。然后,您可以将其映射到实体上的直接 int。这是处理事情的正确方法。