ASP.NET Core [Require]非空类型 [英] ASP.NET Core [Require] non-nullable types
问题描述
此处,提出了一个问题,即如何验证非空值是否必需类型.
Here, the question was posed how to validate non-nullable required types.
在我的情况下,不希望使用提供的使字段为空的解决方案,如下所示.
The provided solution to make the field nullable like the following is not desirable in my case.
[Required]
public int? Data { get; set; }
在请求中省略该字段的情况下,如何更改行为以进行以下失败验证.
How can you change the behavior to instead make the following fail validation in the cases where the field is omitted from the request.
[Required]
public int Data { get; set; }
我尝试了一个自定义验证器,但是这些没有原始值的信息,只能看到默认的0
值.我也尝试过自定义模型绑定程序,但它似乎可以在整个请求模型的级别上工作,而不是在所需的整数字段上工作.我的资料夹实验看起来像这样:
I have tried a custom validator, but these do not have information about the raw value and only see the default 0
value. I have also tried a custom model binder but it seems to work at the level of the entire request model instead of the integer fields which a want. My binder experiment looks like this:
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;
}
}
并在这样的mvc中注册
and is registered with mvc like this
options.ModelBinderProviders.Insert(0, new RequiredIntBinderProvider());
,但从不使用模型联编程序.我觉得我可能很近,但是无法连接最后一个点.
but the model binder is never used. I feel like I might be close but cannot connect the last dots.
推荐答案
解决json请求的解决方案
您无法验证已经创建的模型实例,因为不可为空的属性始终具有一个值(无论它是从json分配还是默认值). 解决方案是报告反序列化过程中已经丢失的值.
Solution working with json requests
You cannot validate an already created model instance, because a non-nullable property has always a value (no matter whether it was assigned from json or is a default value). The solution is to report the missing value already during deserialization.
创建合同解析器
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;
}
}
,然后将其分配给SerializerSettings
:
services.AddMvc()
.AddJsonOptions(jsonOptions =>
{
jsonOptions.SerializerSettings.ContractResolver = new RequiredPropertiesContractResolver();
});
如果json中缺少值,则ModelState
对于具有[Required]
属性的不可为null的属性无效.
The ModelState
is then invalid for non-nullable properties with the [Required]
attribute if the value is missing from json.
Json身体
var jsonBody = @"{ Data2=123 }"
对于模型无效
class Model
{
[Required]
public int Data { get; set; }
public int Data2 { get; set; }
}
这篇关于ASP.NET Core [Require]非空类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!