[英]ASP.NET Core [Require] non-nullable types
這里提出了如何驗證不可空的必需類型的問題。
在我的情況下,所提供的解決方案使得字段可以像以下一樣可空。
[Required]
public int? Data { get; set; }
如何在請求中省略字段的情況下更改行為,而不是進行以下失敗驗證。
[Required]
public int Data { get; set; }
我嘗試過自定義驗證器,但這些驗證器沒有關於原始值的信息,只看到默認的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;
}
}
並在這樣的mvc注冊
options.ModelBinderProviders.Insert(0, new RequiredIntBinderProvider());
但模型活頁夾從未使用過。 我覺得我可能很接近,但無法連接最后的點。
不可空的必需類型。
你不。 它要么是必需的 - 那么它沒有任何意義可以為空 - 或者它不是必需的,那么你可以理智,但是要求它是沒有意義的。
屬性總是針對整個請求。 您遇到了邏輯問題,因為您嘗試不按預期使用它們。
如果它是可選的,則用戶應該實際提交補丁,而不是put / post。
請求中的所有內容都只是一個字符串。 模型綁定器將請求正文中的鍵與屬性名稱進行匹配,然后嘗試將它們強制轉換為適當的類型。 如果屬性未發布或使用空字符串發布,那么在嘗試轉換為int時,這顯然會失敗。 因此,您最終得到了該類型的默認值。 如果int
為0
,則默認值為int?
是null
。
只有在此綁定過程完成后,才會驗證模型。 請記住,您正在驗證模型而不是帖子正文。 沒有合理的方法來驗證帖子正文,因為再次,它只是一堆鍵值對字符串。 因此,如果int
屬性是必需的,但未發布,則該值為0
,這是int的完全有效值,並且滿足驗證。 在int?
的情況下int?
,該值為null
,這不是有效的int,因此驗證失敗。 這就是為什么nullable是必需的,如果你想要一個非可空類型有一個值。 這是將空值與簡單的“默認”值區分開來的唯一方法。
如果您正在使用視圖模型,那么這應該不是問題。 您可以綁定到有需要的屬性的可空INT,你將得到保證,這將有一個價值,盡管是空的,如果你的模型狀態是有效的。 然后,您可以將其映射到實體上的直線int。 這是處理事情的正確方法。
您無法驗證已創建的模型實例 ,因為非可空屬性始終具有值(無論它是從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;
}
}
然后將其分配給SerializerSettings
:
services.AddMvc()
.AddJsonOptions(jsonOptions =>
{
jsonOptions.SerializerSettings.ContractResolver = new RequiredPropertiesContractResolver();
});
如果json缺少值,則ModelState
對於具有[Required]
屬性的非可空屬性無效。
傑森的身體
var jsonBody = @"{ Data2=123 }"
對於模型無效
class Model
{
[Required]
public int Data { get; set; }
public int Data2 { get; set; }
}
有辦法做到這一點,至少它適用於我,嘗試[BindRequired]
為非可空類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.