Asp.net mvc 自定义验证属性-有效整数

Asp.net mvc 自定义验证属性-有效整数,asp.net-mvc,asp.net-mvc-4,Asp.net Mvc,Asp.net Mvc 4,我有一个奇怪的要求 我有一个类,上面有两个属性,如下所示: public class MyViewModel { [EnhancedServiceValidInteger("Name")] public int NumberOfItems { get; set; } public string Name { get; set; } } 上面的类用作用于构建动态表单的动态字段。当NumberOfItems不正确(不是有效的整数)时,应使用Name属性中的值作为Displ

我有一个奇怪的要求

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

public class MyViewModel
{
    [EnhancedServiceValidInteger("Name")]
    public int NumberOfItems { get; set; }

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

我已经实现了一个触发的自定义验证属性,但是如果用户输入了一个字母,我希望该属性能够拾取该字母。在这种情况下(IsValid(object value,…)IsValid methods value属性始终为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);
        }
    }
}
公共类MyCustomValidIntegerValidator:DataAnnotationsModelValidator
{
公共MyCustomValidIntegerValidator(ModelMetadata元数据、ControllerContext上下文、EnhancedServiceValidInteger属性)
:base(元数据、上下文、属性)
{
如果(!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);
}
}
}

关于为什么在将表单值发布回控制器时,
DefaultModelBinder
首先将值绑定到属性(使用
PropertyDescriptor
SetValue()
方法)。由于属性为
int
,且值为
string
,因此无法对其进行设置并指定默认值。直到这个绑定完成,验证过程才开始


不确定如何实现所需,但创建自定义的
ModelBinder
可能是一个选项

如果您使用常用的
EditorFor()
Html帮助程序创建输入字段,请注意,它还将使用
required
创建一个
type=“number”
输入。如果您在其中添加字母,某些浏览器将不会返回值。谢谢Tallmaris,我正在使用@Html.TextboxFor(…)。谢谢Stephen,我将查看模型绑定。您可能还需要将
CustomModelBinderAttribute
应用于属性
NumberOfItems
,这会告诉
ModelBinder
仅将自定义
ModelBinder
用于此属性(您可能不想将其应用于
int
类型的所有属性)。您有任何示例吗?我的Google Fu让我担心的不是这种情况,但是
ModelBinder
有很多方法可以覆盖,比如
OnModelUpdating()
,你应该能够在绑定之前获取发布的值,以及
OnPropertyValidating()
,这在验证之前发生,可能允许你改变行为