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

时间:2019-01-15 16:21:43

标签: c# enums asp.net-core-webapi asp.net-core-webapi-2.1

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

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

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

AddressType枚举接受两个值:

[JsonConverter(typeof(StringEnumConverter))]
public enum AddressType
{
    [EnumMember(Value = "Dropship")]
    Dropship,
    [EnumMember(Value = "Shipping")]
    Shipping
}

我已经注意到(或实际上我的质量检查团队已经注意到),如果请求消息JSON包含AddressType的空字符串或null,则错误消息不是预期的Address type is required.消息。相反,该错误消息是某种程度上不友好的解析错误。

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

{  "addressType": "" }

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

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

如果某人未包含枚举的有效值,是否可以确保返回[Required]属性的错误消息?

4 个答案:

答案 0 :(得分:1)

选项1:使用Custom RequiredEnum属性并避免使用JsonConverter属性

不要将JsonConverter放在AddressType枚举上。此StringToEnum无法将string.Empty映射到枚举值,并引发此错误消息。

相反,您可以编写一个自定义的必需枚举验证器,如下所示。

    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);
        }
   }

然后您可以如下所示使用它:

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

选项2:将自定义JsonConverter用于AddressType

添加一个从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);
    }
}

使用此jsonConverter代替默认的StringEnumConverter,如下所示

[JsonConverter(typeof(CustomStringToEnumConverter))]
public enum AddressType
{
}

答案 1 :(得分:0)

我认为没有现成的数据注释可以验证枚举值。

不过,您可以从所需的属性派生

using System;
using System.ComponentModel.DataAnnotations;

    public class RequiredEnumAttribute : RequiredAttribute
    {
        public override bool IsValid(object value)
        {
            if (value == null) return false;
            var type = value.GetType();
            return type.IsEnum && Enum.IsDefined(type, value);
        }
}

Enum.IsDefined方法正在检查给定value的枚举中是否存在给定的type

用法:

[RequiredEnum(ErrorMessage = "Your error message.")]
public YourEnum EnumProperty { get; set; }

请参阅this文章。

答案 2 :(得分:0)

尽管代码使我有些畏缩,但我想出了一个满足我要求的解决方案。

我在视图模型的[Required]属性上保留了AddressType属性。最令人毛骨悚然的部分是,我必须将属性nullable

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

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

[JsonConverter(typeof(CustomStringToEnumConverter))]
public enum AddressType
{
    [EnumMember(Value = "Dropship")]
    Dropship,
    [EnumMember(Value = "Shipping")]
    Shipping
}

这是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;
        }
    }
}

CustomerStringToEnumConverter可以处理空字符串,空值和无效字符串。如果遇到无效的枚举值,它将返回null,然后在进行所需的字段验证(魔术)并在JSON响应中显示RequiredAttribute错误消息时被捕获。

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

答案 3 :(得分:0)

(在此处查看完整文章:https://mtarleton.medium.com/enum-as-required-field-in-asp-net-core-webapi-a79b697ef270

这里面临的问题是将正文转换为 JSON 和验证模型验证的操作顺序。

首先,.NET 将正文反序列化为具有默认值的 JSON 。这意味着如果您为不可为空的 ENUM 传入一个空值,则将为它设置默认值(通常是 ENUM 中的第一项)。同样的事情发生在原始生物身上。

[JsonProperty(Required = Required.Always)]