【问题标题】:Asp.Net MVC Validation - dependent fieldsAsp.Net MVC 验证 - 依赖字段
【发布时间】:2011-01-01 20:37:45
【问题描述】:

我目前正在尝试通过 MVC 验证工作,并且遇到了一些问题,即根据另一个字段的值需要一个字段。下面是一个示例(我还没有弄清楚) - 如果 PaymentMethod == "Cheque",则应该需要 ChequeName,否则可以通过。

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

[Required(ErrorMessage = "ChequeName is required")]
public override string ChequeName
{ get; set; }

我将 System.ComponentModel.DataAnnotations 用于 [Required],并且还扩展了 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")]

有没有人有过这种验证的经验?将其写入控制器会更好吗?

感谢您的帮助。

【问题讨论】:

  • 再想一想...您如何设置 PaymentSelected = PaymentMethod?你应该得到一个错误,因为 PaymentMethod 不是一个常量表达式。
  • 嗨,敏,你是对的。我以为我可以这样做,但它不起作用。我只是想展示我尝试过的东西,但也评论说它不允许我通过变量。

标签: asp.net asp.net-mvc validation


【解决方案1】:

如果除了服务器上的模型验证之外还需要客户端验证,我认为最好的方法是自定义验证属性(如 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; }

【讨论】:

  • 我意识到这个答案已经有 2 年历史了,但我正试图让它发挥作用,基本上不管第一个属性的值是什么,它都会触发对依赖属性的验证。任何帮助将不胜感激。
【解决方案2】:

只需使用 Codeplex 上提供的 Foolproof 验证库: https://foolproof.codeplex.com/

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

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

上手很简单:

  1. 从提供的链接下载包
  2. 添加对包含的 .dll 文件的引用
  3. 导入包含的 javascript 文件
  4. 确保您的视图从其 HTML 中引用包含的 javascript 文件,以实现不显眼的 javascript 和 jquery 验证。

【讨论】:

    【解决方案3】:

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

    对于依赖于另一个属性或字段的值的验证,我(不幸的是)看不到如何完全避免在模型中为此编写一些代码,例如 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,但这只会处理这种类型的逻辑。稍微复杂一点的东西需要另一个非常具体的属性,等等,这很快就会变得疯狂。

    【讨论】:

    • 感谢 djuth,我已经使用 ModelStateDictionary 并在模型中对此进行了验证,然后将字典传递回控制器以合并到 ModelState 中。似乎可以做到这一点,并允许我做一些程序化的工作——仅仅为每个属性做一个声明并不那么好,但至少我可以在一个地方得到所有的东西。如果每个属性有多个错误,不知道会怎样。
    【解决方案4】:

    你的问题可以通过conditional validation attribute的用法相对简单地解决,例如

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

    【讨论】:

      猜你喜欢
      • 2012-09-13
      • 2016-05-27
      • 2011-04-27
      • 1970-01-01
      • 1970-01-01
      • 2015-04-04
      • 2013-09-12
      • 2020-04-17
      • 1970-01-01
      相关资源
      最近更新 更多