代码之家  ›  专栏  ›  技术社区  ›  Ronnie Overby

自定义ModelValidator的ASP.NET MVC 2问题

  •  1
  • Ronnie Overby  · 技术社区  · 14 年前

    我正在尝试验证视图中的两个文本框字段中是否提供了值。我做了这个模型验证器:

    public class RequireEitherValidator : ModelValidator
    {
        private readonly string compareProperty;
        private readonly string errorMessage;
    
        public RequireEitherValidator(ModelMetadata metadata,
        ControllerContext context, string compareProperty, string errorMessage)
            : base(metadata, context)
        {
            this.compareProperty = compareProperty;
            this.errorMessage = errorMessage;
        }
    
        public override IEnumerable<ModelValidationResult> Validate(object container)
        {
            if (Metadata.Model == null)
                yield break;
            var propertyInfo = container.GetType().GetProperty(compareProperty);
            if (propertyInfo == null)
                throw new InvalidOperationException("Unknown property:" + compareProperty);
    
            string valueToCompare = propertyInfo.GetValue(container, null).ToString();
    
            if (string.IsNullOrEmpty(Metadata.Model.ToString()) && string.IsNullOrEmpty(valueToCompare))
                yield return new ModelValidationResult
                {
                    Message = errorMessage
                };
        }
    }
    

    这个验证逻辑永远不会被击中,我认为这是因为没有值被提供给文本框。

    如果您需要它,下面是我创建的提供程序和属性以及属性用法:

    public class MyValidatorProvider : AssociatedValidatorProvider
    {
        protected override IEnumerable<ModelValidator> GetValidators(
            ModelMetadata metadata, ControllerContext context,
            IEnumerable<Attribute> attributes)
        {
            foreach (var attrib in attributes.OfType<RequireEitherAttribute>())
                yield return new RequireEitherValidator(metadata, context,
                attrib.CompareProperty, attrib.ErrorMessage);
        }
    }
    
    public class RequireEitherAttribute : Attribute
    {
        public readonly string CompareProperty;
        public string ErrorMessage { get; set; }
    
        public RequireEitherAttribute(string compareProperty)
        {
            CompareProperty = compareProperty;
        }
    }
    
    public class StudentLogin
    {
        [DisplayName("Last Name")]
        [Required(ErrorMessage = "You must supply your last name.")]        
        public string LastName { get; set; }
    
        [DisplayName("Student ID")]
        [RegularExpression(@"^\d{1,8}$", ErrorMessage = "Invalid Student ID")]
        [RequireEither("SSN", ErrorMessage = "You must supply your student id or social security number.")]        
        public int? StudentId { get; set; }
    
        [DisplayName("Social Security Number")]
        [RegularExpression(@"^\d{9}|\d{3}-\d{2}-\d{4}$", ErrorMessage = "Invalid Social Security Number")]
        public string SSN { get; set; }
    }
    

    我的看法是:

     <%Html.BeginForm(); %>
        <p>
            Please supply the following information to login:</p>
        <ol class="standard">
            <li>
                <p>
                    <%=Html.LabelFor(x => x.LastName) %><br />
                    <%=Html.TextBoxFor(x => x.LastName)%>
                    <%=Html.ValidationMessageFor(x => x.LastName) %></p>
            </li>
            <li>
                <p>
                    <%=Html.LabelFor(x => x.StudentId) %><br />
                    <%=Html.TextBoxFor(x => x.StudentId) %>
                    <%=Html.ValidationMessageFor(x => x.StudentId) %></p>
                <p style="margin-left: 4em;">
                    - OR -</p>
                <p>
                    <%=Html.LabelFor(x => x.SSN)%><br />
                    <%=Html.TextBoxFor(x => x.SSN) %>
                    <%=Html.ValidationMessageFor(x => x.SSN) %>
                </p>
            </li>
        </ol>
        <%=Html.SubmitButton("submit", "Login") %>
        <%Html.EndForm(); %>
    
    3 回复  |  直到 14 年前
        1
  •  1
  •   Steve Michelotti    14 年前

    实现这一点的一种方法不仅仅是创建一个validationattribute并在类级别应用它。

    [RequireEither("StudentId", "SSN")]
    public class StudentLogin
    

    错误消息将自动显示在验证摘要中。这个属性看起来像这样(我已经彻底简化了isvalid()中的验证逻辑,将所有内容都视为字符串,只是为了简洁:

    public class RequireEither : ValidationAttribute
    {
        private string firstProperty;
        private string secondProperty;
    
        public RequireEither(string firstProperty, string secondProperty)
        {
            this.firstProperty = firstProperty;
            this.secondProperty = secondProperty;
        }
    
        public override bool IsValid(object value)
        {
            var firstValue = value.GetType().GetProperty(this.firstProperty).GetValue(value, null) as string;
            var secondValue = value.GetType().GetProperty(this.secondProperty).GetValue(value, null) as string;
    
            if (!string.IsNullOrWhiteSpace(firstValue))
            {
                return true;
            }
    
            if (!string.IsNullOrWhiteSpace(secondValue))
            {
                return true;
            }
            // neither was supplied so it's not valid
            return false;
        }
    }
    

    注意,在这种情况下,传递给isvalid()的对象是类本身的实例,而不是属性。

        2
  •  1
  •   psousa    14 年前

    我喜欢Steve和Ronnie解决方案,虽然它们创建的自定义属性可以用于其他类/属性对,但我不喜欢这种简单的情况下的“魔力字符串”和反射,我通常创建一个验证,它只适合手头的场景。

    例如,在本例中,我将创建如下内容:

    [AttributeUsage(AttributeTargets.Class)]
    public class RequireStudentInfoAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
            var student = value as StudentLogin;
            if(student == null)
            {
                return false;
            }
    
            if (student.StudentId.HasValue || !string.IsNullOrEmpty(student.SSN))
            {
                return true;
            }
    
            return false;
        }
    }
    

    只需将其应用于studentlogin类,如:

    [RequireStudentInfo]
    public class StudentLogin
    

    关于客户端验证,我通常会 http://xval.codeplex.com/ ,因为它与数据注释集成得非常好

        3
  •  0
  •   Ronnie Overby    14 年前

    使用了史蒂夫的建议,只是做了一些细微的改动:

    public class RequireEitherAttribute : ValidationAttribute
    {
        private string firstProperty;
        private string secondProperty;
    
        public RequireEitherAttribute(string firstProperty, string secondProperty)
        {
            this.firstProperty = firstProperty;
            this.secondProperty = secondProperty;
        }
    
        public override bool IsValid(object value)
        {
            object firstValue = value.GetType().GetProperty(firstProperty).GetValue(value, null);
            object secondValue = value.GetType().GetProperty(secondProperty).GetValue(value, null);
    
            return InputSupplied(firstValue) || InputSupplied(secondValue);
        }
    
        private bool InputSupplied(object obj)
        {
            if (obj == null)
                return false;
    
            if (obj is string)
            {
                string str = (string)obj;
    
                if (str.Trim() == string.Empty)
                    return false;
            }
    
            return true;
        }
    }
    

    因为这不是属性级验证,所以我必须向视图中添加验证摘要。

    我仍然很好奇如何将此与客户端验证挂钩。