枚举作为 ASP.NET Core WebAPI 中的必填字段

Poo*_*eld 8 c# enums asp.net-core-webapi

[Required]当 JSON 请求没有为枚举属性提供正确的值时,是否可以返回属性错误消息?

例如,我有一个包含AddressType枚举类型属性的 POST 消息模型:

public class AddressPostViewModel
{
    [JsonProperty("addressType")]
    [Required(ErrorMessage = "Address type is required.")]
    public AddressType AddressType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

AddressType枚举接受两个值:

[JsonConverter(typeof(StringEnumConverter))]
public enum AddressType
{
    [EnumMember(Value = "Dropship")]
    Dropship,
    [EnumMember(Value = "Shipping")]
    Shipping
}
Run Code Online (Sandbox Code Playgroud)

我注意到(或者实际上我的 QA 团队注意到)如果请求消息 JSON 包含空字符串或 null AddressType,则错误消息不是预期的Address type is required.消息。相反,错误消息是一个有点不友好的解析错误。

例如,如果请求 JSON 如下所示:

{  "addressType": "" }
Run Code Online (Sandbox Code Playgroud)

然后验证框架自动生成的错误如下所示:

{
    "message": "Validation Failed",
    "errors": [
        {
            "property": "addressType",
            "message": "Error converting value \"\" to type 'MyNamespace.AddressType'. Path 'addressType', line 4, position 19."
        }
    ]
}
Run Code Online (Sandbox Code Playgroud)

[Required]如果有人不包含枚举的有效值,有没有办法确保返回属性的错误消息?

Man*_*ari 6

选项 1:使用自定义 RequiredEnum 属性并避免 JsonConverter 属性

不要将 JsonConverter 放在 AddressType 枚举上。此 StringToEnum 未能将 string.Empty 映射到 enum 值,并抛出此错误消息。

取而代之的是,您可以编写自定义所需的枚举验证器,如下所示。

    using System;
    using System.ComponentModel.DataAnnotations;

    public class RequiredEnumFieldAttribute: RequiredAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null)
            {
                 return false;
            }

            var type = value.GetType();
            return type.IsEnum && Enum.IsDefined(type, value);
        }
   }
Run Code Online (Sandbox Code Playgroud)

然后你可以像下图一样使用它:

public class AddressPostViewModel
{
    [JsonProperty("addressType")]
    [RequiredEnumField(ErrorMessage = "Address type is required.")]
    public AddressType AddressType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

选项 2:为 AddressType 使用自定义 JsonConverter

添加一个从 StringEnumConverter 派生的自定义 CustomStringToEnumConverter。

如果 JSON 中的值为空,则此方法将引发错误。

public class CustomStringToEnumConverter : StringEnumConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (string.IsNullOrEmpty(reader.Value.ToString()))
            throw new Exception("Address not provided");

        return base.ReadJson(reader, objectType, existingValue, serializer);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这个 jsonConverter 而不是默认的 StringEnumConverter 如下所示

[JsonConverter(typeof(CustomStringToEnumConverter))]
public enum AddressType
{
}
Run Code Online (Sandbox Code Playgroud)


Poo*_*eld 5

我已经想出了一个满足我的要求的解决方案,尽管代码让我有点畏缩。

我将属性[Required]的属性保留AddressType在视图模型中。令人畏缩的部分是我必须制作该财产nullable

public class AddressPostViewModel
{
    [JsonProperty("addressType")]
    [Required(ErrorMessage = "Address type is required.")]
    public AddressType? AddressType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

AttributeType枚举本身上,我按照 @Manoj Choudhari 的建议StringEnumConverter用自定义替换了该属性:JsonConverter

[JsonConverter(typeof(CustomStringToEnumConverter))]
public enum AddressType
{
    [EnumMember(Value = "Dropship")]
    Dropship,
    [EnumMember(Value = "Shipping")]
    Shipping
}
Run Code Online (Sandbox Code Playgroud)

这是CustomStringToEnumConverter

public class CustomStringToEnumConverter : StringEnumConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (string.IsNullOrEmpty(reader.Value?.ToString()))
        {
            return null;
        }

        object parsedEnumValue;

        var isValidEnumValue = Enum.TryParse(objectType.GenericTypeArguments[0], reader.Value.ToString(), true, out parsedEnumValue);

        if (isValidEnumValue)
        {
            return parsedEnumValue;
        }
        else
        {
            return null;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可以CustomStringToEnumConverter处理空字符串、空值和无效字符串。如果遇到无效的枚举值,则会返回null该值,然后在发生必需的字段验证(魔术)时捕获该值,并RequiredAttribute在 JSON 响应中显示错误消息。

虽然我不喜欢使类型可为空,但如果请求 JSON 中的值错误,AttributeType我的 API 的使用者将看到一致的验证消息。AttributeType