当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]
属性的错误消息?
答案 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)]