簡體   English   中英

ASP.NET Core [要求]非可空類型

[英]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時,這顯然會失敗。 因此,您最終得到了該類型的默認值。 如果int0 ,則默認值為int? null

只有在此綁定過程完成后,才會驗證模型。 請記住,您正在驗證模型而不是帖子正文。 沒有合理的方法來驗證帖子正文,因為再次,它只是一堆鍵值對字符串。 因此,如果int屬性是必需的,但未發布,則該值為0 ,這是int的完全有效值,並且滿足驗證。 int?的情況下int? ,該值為null ,這不是有效的int,因此驗證失敗。 這就是為什么nullable是必需的,如果你想要一個非可空類型有一個值。 這是將空值與簡單的“默認”值區分開來的唯一方法。

如果您正在使用視圖模型,那么這應該不是問題。 您可以綁定到有需要的屬性的可空INT,你將得到保證,這有一個價值,盡管是空的,如果你的模型狀態是有效的。 然后,您可以將其映射到實體上的直線int。 這是處理事情的正確方法。

使用json請求的解決方案

無法驗證已創建的模型實例 ,因為非可空屬性始終具有值(無論它是從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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM