DataAnnotations命名空间中是否有适用于枚举值的开箱即用验证器?

23

C# 枚举值不仅限于定义中列出的值,还可以存储任何其基础类型的值。如果未定义基础类型,则使用 Int32 或简单的 int

我正在开发一个 WCF 服务,需要确保某个枚举有一个指定的值,而不是所有枚举默认值为 0。我从一个单元测试开始,以确定 [Required] 是否适用于此处。

using System.ComponentModel.DataAnnotations;
using Xunit;

public enum MyEnum
{
    // I always start from 1 in order to distinct first value from the default value
    First = 1,
    Second,
}

public class Entity
{
    [Required]
    public MyEnum EnumValue { get; set; }
}

public class EntityValidationTests
{
    [Fact]
    public void TestValidEnumValue()
    {
        Entity entity = new Entity { EnumValue = MyEnum.First };

        Validator.ValidateObject(entity, new ValidationContext(entity, null, null));
    }

    [Fact]
    public void TestInvalidEnumValue()
    {
        Entity entity = new Entity { EnumValue = (MyEnum)(-126) };
        // -126 is stored in the entity.EnumValue property

        Assert.Throws<ValidationException>(() =>
            Validator.ValidateObject(entity, new ValidationContext(entity, null, null)));
    }
}

第二个测试未抛出任何异常。

我的问题是:是否有验证器属性可检查提供的值是否在Enum.GetValues中?

更新。 请确保在我的单元测试中使用ValidateObject(Object, ValidationContext, Boolean),并将最后一个参数设置为True,而不是像之前使用ValidateObject(Object, ValidationContext)


我从未使用过它,所以我不知道它是否检查值,但你可以尝试使用EnumDataTypeAttribute:http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.enumdatatypeattribute%28v=vs.95%29.aspx - Raphaël Althaus
3个回答

36

.NET4+中有 EnumDataType ...

在调用ValidateObject时,请确保设置第三个参数validateAllProperties=true

所以,根据您的示例:

public class Entity
{
    [EnumDataType(typeof(MyEnum))]
    public MyEnum EnumValue { get; set; }
}

[Fact]
public void TestInvalidEnumValue()
{
    Entity entity = new Entity { EnumValue = (MyEnum)(-126) };
    // -126 is stored in the entity.EnumValue property

    Assert.Throws<ValidationException>(() =>
        Validator.ValidateObject(entity, new ValidationContext(entity, null, null), true));
}

刚从 [Required] 切换到 [EnumDataType(typeof(MyEnum))] 并进行了测试,仍未出现 ValidationException - Mike
你尝试过在ValidateObject调用的第三个参数中添加true吗? - qujck
好的!现在它可以工作了。只有 [EnumDataType(typeof(MyEnum))],没有 [Required],我使用 validateAllProperties=true 调用 ValidateObject。你能否更新你的答案,展示正确的验证方法,这样我就可以接受它? - Mike

11

你要找的是:

 Enum.IsDefined(typeof(MyEnum), entity.EnumValue)

[更新+1]

开箱即用的验证器,包括此验证,被称为EnumDataType。确保你将validateAllProperties=true设置为ValidateObject,否则你的测试将失败。

如果你只想检查枚举是否已定义,你可以使用上述代码行的自定义验证器。

    [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false)]
    public sealed class EnumValidateExistsAttribute : DataTypeAttribute
    {
        public EnumValidateExistsAttribute(Type enumType)
            : base("Enumeration")
        {
            this.EnumType = enumType;
        }

        public override bool IsValid(object value)
        {
            if (this.EnumType == null)
            {
                throw new InvalidOperationException("Type cannot be null");
            }
            if (!this.EnumType.IsEnum)
            {
                throw new InvalidOperationException("Type must be an enum");
            }
            if (!Enum.IsDefined(EnumType, value))
            {
                return false;
            }
            return true;
        }

        public Type EnumType
        {
            get;
            set;
        }
    }

...但我想这不是一个开箱即用的解决方案,不是吗?


这个有用的方法值得一加。它已经存在多年,但我从未注意到它。 - Mike
@RaphaëlAlthaus 你说得完全正确。对此感到抱歉,我已更改了我的答案并进行了测试,现在它可以工作了。 - atlaste
@StefandeBruijn 好的,加一。 - Raphaël Althaus
1
在最后一步,您可以简单地使用 return Enum.IsDefined(EnumType, value) - Sergey Berezovskiy
谢谢大家的努力。事实证明,EnumDataType 已经完成了它的工作。我只需要包括 validateAllProperties=true 即可。 - Mike
这可能不是什么大问题,但为什么不使用ValidationContext自动获取枚举类型呢?或者更好的方法是直接使用value.GetType() - Anthony Iacono

1

我根据这个网站https://kristinaalberto.com/making-enum-parameters-required-in-asp-net-core-mvc/简单地解决了我的需求。

    public enum CreatedBySelfOrOthersEnumValues
    {
        Self,
        Others
    }

  
    public class CampaignRegisterValidationModel
    {
        [Required]
        public string Name { get; set; }

        [Required]
        public CreatedBySelfOrOthersEnumValues CreatedForSelfOrOthers { get; set; }

        [Required]
        public int CountryCode { get; set; }

        public string Phone { get; set; }
        public string Email { get; set; }
    }

然后验证。
     if (ModelState.IsValid)
     {
     }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接