自定义验证属性 - 有效整数

Posted

技术标签:

【中文标题】自定义验证属性 - 有效整数【英文标题】:Custom Validation Attribute - Valid Integer 【发布时间】:2014-08-11 10:29:11 【问题描述】:

我有一个奇怪的要求。

我有一个类,上面有 2 个属性,如下所示:

public class MyViewModel

    [EnhancedServiceValidInteger("Name")]
    public int NumberOfItems  get; set; 

    public string Name  get; set; 

上面的类用作动态字段,用于构建动态表单。当 NumberOfItems 不正确(不是有效整数)时,应使用 Name 属性中的值作为 DisplayName 来显示错误消息,并且是任何错误消息的输出。

我已经实现了一个触发的自定义验证属性,但是如果用户输入一个字母,我希望该属性能够接收该字母。在这种情况下 (IsValid(object value, ...)) IsValid 方法值属性始终为 0,因此验证通过并且 MyCustomValidIntegerValidator 中没有断点被命中。如果这是在 UI 中输入的值,为什么不将值设置为“aaa”?

有人可以帮忙吗?

我有以下自定义验证属性:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false)]
public class MyCustomValidInteger : ValidationAttribute

    private readonly string _validationNameFromProperty;

    public EnhancedServiceValidInteger(string validationNameFromProperty) : base("0 contains invalid character.")
    
        _validationNameFromProperty = validationNameFromProperty;
    

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    
        // the the other property
        var property = validationContext.ObjectType.GetProperty(_validationNameFromProperty);

        // check it is not null
        if (property == null)
        
            return new ValidationResult(String.Format("Unknown property: 0.", _validationNameFromProperty));
        

        // get the other value
        var nameToUse = property.GetValue(validationContext.ObjectInstance, null).ToString();

        if (value == null || value.ToString().Length == 0)
        
            return ValidationResult.Success;
        

        int i;

        var errorMessage = string.Format("The value '0' is not valid for 1", value, nameToUse);

        ValidationResult validationResult = !int.TryParse(value.ToString(), out i) ? new ValidationResult(errorMessage) : ValidationResult.Success;

        return validationResult;
    

这是上述类的 DataAnnotationsModelValidator 实现:

public class MyCustomValidIntegerValidator : DataAnnotationsModelValidator<MyCustomValidInteger>

    public MyCustomValidIntegerValidator(ModelMetadata metadata, ControllerContext context, EnhancedServiceValidInteger attribute) 
        : base(metadata, context, attribute)
    
        if (!attribute.IsValid(context.HttpContext.Request.Form[metadata.PropertyName]))
        
            var propertyName = metadata.PropertyName;
            context.Controller.ViewData.ModelState[propertyName].Errors.Clear();
            context.Controller.ViewData.ModelState[propertyName].Errors.Add(attribute.ErrorMessage);
        
    

【问题讨论】:

如果您使用通常的EditorFor() html 帮助程序创建输入字段,请注意它也会使用required 创建一个type="number" 输入。如果您在其中输入字母,某些浏览器将不会返回值。 感谢 Tallmaris,我正在使用 @Html.TextboxFor(...)。 【参考方案1】:

至于为什么,当表单值回传到控制器时,DefaultModelBinder 首先将值绑定到属性(使用PropertyDescriptorSetValue() 方法)。由于属性是int,值是string,所以不能设置,分配默认值。直到此绑定完成,验证过程才开始。

不确定如何实现您想要的,但创建自定义 ModelBinder 可能是一种选择

【讨论】:

谢谢斯蒂芬,我会看看模型活页夹 您可能还需要将CustomModelBinderAttribute 应用于属性NumberOfItems,它告诉ModelBinder 仅将您的自定义ModelBinder 用于此属性(您可能不想应用它到 int) 类型的所有属性 你有例子吗?我的 Google-Fu 让我失望了 对不起,不是这种情况,但ModelBinder 有很多方法可以覆盖,例如OnModelUpdating(),您应该能够在绑定之前获取发布的值,OnPropertyValidating() 发生在之前可能允许您改变行为的验证

以上是关于自定义验证属性 - 有效整数的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET 4.5 自定义验证属性。 IsValid() 调用太晚了

用于 TextInput 的 Flex 自定义验证器

自定义验证属性不触发 jQuery 验证

spring boot中自定义验证的参数化junit测试

jQuery Unobtrusive 客户端验证自定义属性

MVC 自定义属性验证登录