代码之家  ›  专栏  ›  技术社区  ›  Sam J

ASP.NET MVC验证-依赖字段

  •  7
  • Sam J  · 技术社区  · 15 年前

    我目前正在尝试通过MVC验证,并且遇到了一些问题,即根据另一个字段的值需要一个字段。下面是一个例子(我还没弄清楚)-如果paymentmethod==“check”,那么应该需要支票名,否则可以让它通过。

    [Required(ErrorMessage = "Payment Method must be selected")]
    public override string PaymentMethod
    { get; set; }
    
    [Required(ErrorMessage = "ChequeName is required")]
    public override string ChequeName
    { get; set; }
    

    我正在为[Required]使用System.ComponentModel.DataAnnotations,并且还扩展了一个validationAttribute来尝试使其正常工作,但我无法通过变量进行验证(下面的扩展)

    public class JEPaymentDetailRequired : ValidationAttribute 
    {
        public string PaymentSelected { get; set; }
        public string PaymentType { get; set; }
    
        public override bool IsValid(object value)
        {
            if (PaymentSelected != PaymentType)
                return true;
            var stringDetail = (string) value;
            if (stringDetail.Length == 0)
                return false;
            return true;
        }
    }
    

    实施:

    [JEPaymentDetailRequired(PaymentSelected = PaymentMethod, PaymentType = "Cheque", ErrorMessage = "Cheque name must be completed when payment type of cheque")]
    

    有没有人有过这种验证的经验?把它写进控制器会更好吗?

    谢谢你的帮助。

    4 回复  |  直到 9 年前
        1
  •  3
  •   djuth    15 年前

    我将在模型中编写验证逻辑,而不是控制器。控制器应该只处理视图和模型之间的交互。因为它是需要验证的模型,所以我认为它被广泛认为是验证逻辑的地方。

    对于依赖于另一个属性或字段值的验证,我(不幸的是)看不到如何完全避免在模型中为此编写一些代码,如Wrox ASP.NET MVC手册中所示,有点像:

    public bool IsValid
    {
      get 
      {
        SetRuleViolations();
        return (RuleViolations.Count == 0); 
      }
    }
    
    public void SetRuleViolations()
    {
      if (this.PaymentMethod == "Cheque" && String.IsNullOrEmpty(this.ChequeName))
      {
        RuleViolations.Add("Cheque name is required", "ChequeName");
      }
    }
    

    声明性地进行所有验证是很好的。我相信你可以 RequiredDependentAttribute ,但这只能处理这一类逻辑。更为复杂的东西还需要另一个非常具体的属性,等等,这会很快变得疯狂。

        2
  •  4
  •   PeaceFrog    12 年前

    如果除了服务器上的模型验证之外还需要客户端验证,我认为最好的方法是自定义验证属性(如Jaroslaw建议的那样)。我在这里包括我使用的那个的来源。

    自定义属性:

    public class RequiredIfAttribute : DependentPropertyAttribute
    {
        private readonly RequiredAttribute innerAttribute = new RequiredAttribute();
    
        public object TargetValue { get; set; }
    
    
        public RequiredIfAttribute(string dependentProperty, object targetValue) : base(dependentProperty)
        {
            TargetValue = targetValue;
        }
    
    
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            // get a reference to the property this validation depends upon
            var containerType = validationContext.ObjectInstance.GetType();
            var field = containerType.GetProperty(DependentProperty);
    
            if (field != null)
            {
                // get the value of the dependent property
                var dependentvalue = field.GetValue(validationContext.ObjectInstance, null);
    
                // compare the value against the target value
                if ((dependentvalue == null && TargetValue == null) ||
                    (dependentvalue != null && dependentvalue.Equals(TargetValue)))
                {
                    // match => means we should try validating this field
                    if (!innerAttribute.IsValid(value))
                        // validation failed - return an error
                        return new ValidationResult(ErrorMessage, new[] { validationContext.MemberName });
                }
            }
    
            return ValidationResult.Success;
        }
    
        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
                           {
                               ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
                               ValidationType = "requiredif"
                           };
    
            var depProp = BuildDependentPropertyId(DependentProperty, metadata, context as ViewContext);
    
            // find the value on the control we depend on;
            // if it's a bool, format it javascript style 
            // (the default is True or False!)
            var targetValue = (TargetValue ?? "").ToString();
            if (TargetValue != null)
                if (TargetValue is bool)
                    targetValue = targetValue.ToLower();
    
            rule.ValidationParameters.Add("dependentproperty", depProp);
            rule.ValidationParameters.Add("targetvalue", targetValue);
    
            yield return rule;
        }
    }
    

    jquery验证扩展:

    $.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'targetvalue'], function (options) {
        options.rules['requiredif'] = {
            dependentproperty: options.params['dependentproperty'],
            targetvalue: options.params['targetvalue']
        };
        options.messages['requiredif'] = options.message;
    });
    
    $.validator.addMethod('requiredif',
        function (value, element, parameters) {
            var id = '#' + parameters['dependentproperty'];
    
            // get the target value (as a string, 
            // as that's what actual value will be)
            var targetvalue = parameters['targetvalue'];
            targetvalue = (targetvalue == null ? '' : targetvalue).toString();
    
            // get the actual value of the target control
            var actualvalue = getControlValue(id);
    
            // if the condition is true, reuse the existing 
            // required field validator functionality
            if (targetvalue === actualvalue) {
                return $.validator.methods.required.call(this, value, element, parameters);
            }
    
            return true;
        }
    );
    

    用属性修饰属性:

    [Required]
    public bool IsEmailGiftCertificate { get; set; }
    
    [RequiredIf("IsEmailGiftCertificate", true, ErrorMessage = "Please provide Your Email.")]
    public string YourEmail { get; set; }
    
        3
  •  4
  •   user3083619    11 年前

    只需使用codeplex上提供的万无一失验证库: https://foolproof.codeplex.com/

    它支持以下“RequireDif”验证属性/装饰:

    [RequiredIf]
    [RequiredIfNot]
    [RequiredIfTrue]
    [RequiredIfFalse]
    [RequiredIfEmpty]
    [RequiredIfNotEmpty]
    [RequiredIfRegExMatch]
    [RequiredIfNotRegExMatch]
    

    开始很容易:

    1. 从提供的链接下载包
    2. 添加对包含的.dll文件的引用
    3. 导入包含的javascript文件
    4. 确保视图引用其HTML中包含的javascript文件,以进行不引人注目的javascript和jquery验证。
        4
  •  2
  •   jwaliszko    9 年前

    通过使用 conditional validation attribute 例如

    [RequiredIf("PaymentMethod == 'Cheque'")]
    public string ChequeName { get; set; }