使用DataAnnotationsModelValidator适配器进行MVC3远程验证

时间:2013-03-14 16:29:20

标签: asp.net-mvc asp.net-mvc-3 data-annotations model-validation remote-validation

我想使用自定义DataAnnotationsAttribute验证模型的DTO属性上的各种电话号码属性。我不想将DataAnnotations复制到ViewModel上,以保持代码DRY,而是使用DataAnnotationsModelValidatorProvider为客户端验证注册了自定义适配器。此适配器提供ModelClientValidationRemoteRules,通常由RemoteAttribute使用。 jQuery不显眼的验证然后调用我的验证操作,验证各个字段。

然而,这种设置并不合适。

  1. 该属性当前使用其ContainerType来计算出哪个 要调用的验证操作。 DTO用于不同的视图模型 然而,在不同的筑巢水平,所以我们不知道到底是什么 在动作上使用的前缀。取决于ProfileDto的位置 在模型层次结构中,操作前缀需要更改

  2. 验证操作使用Request.Form.Keys来确定哪个 属性应该验证。我知道这是最好的做法 为单位而远离Action中的Request对象 测试等。

  3. 是否有一种很好的方法可以在回发中包含要验证的字段名称,因此我可以将其作为附加参数而不是使用Request.Form?

    有没有办法让模型绑定器绑定我的属性,因为它们将使用取决于子模型名称的前缀回发?

    提前致谢!


    该属性如下:

    public class PhoneNumberAttribute : ValidationAttribute
    {
        public PhoneNumberType RequiredType { get; set; }
    
        public PhoneNumberAttribute()
            : base("{0} is not a valid phone number.")
        {
        }
    
        public override bool IsValid(object value)
        {
            string s = value as string;
            if (s == null)
            {
                return false;
            }
            if (!PhoneNumberUtils.IsValidNumber(s, RequiredType))
            {
                return false;
            }
    
            return true
        }
    
        public override string FormatErrorMessage(string name)
        {
            return string.Format(ErrorMessageString, name);
        }
    }
    

    和适配器:

    public class PhoneNumberAttributeAdapter : DataAnnotationsModelValidator<PhoneNumberAttribute>
    {
        public PhoneNumberAttributeAdapter(ModelMetadata metadata, ControllerContext context, PhoneNumberAttribute attribute)
            : base(metadata, context, attribute)
        {
        }
    
        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            var errorMessage = Attribute.FormatErrorMessage(Metadata.GetDisplayName());
            var routeData = new RouteValueDictionary { 
                { "controller", "Validate" },
                { "action", Metadata.ContainerType.Name },
            };
    
            var path = RouteTable.Routes.GetVirtualPathForArea(ControllerContext.RequestContext, routeData);
    
            var rule = new ModelClientValidationRemoteRule(
                errorMessage, 
                path.VirtualPath, 
                "POST", 
                "*." + Metadata.PropertyName);
    
            return new[] { rule };
        }
    }
    

    这是行动:

    public ActionResult ProfileDto([Bind(Prefix = "Dto")]ProfileDto model)
    {
        string fieldToValidate = Request.Form.Keys[0];
        if (ModelState.IsValidField(fieldToValidate))
        {
            return Json(true);
        }
    
        var fieldErrors = ModelState[fieldToValidate].Errors;
    
        return Json(fieldErrors.First().ErrorMessage);
    }
    

1 个答案:

答案 0 :(得分:0)

看一下这个例子here,其中展示了如何在自定义jQuery验证器中使用前缀获取嵌套属性。

其次,MVC模型绑定器应自动绑定您的前缀。