Asp.Net MVC验证 - 依赖字段

时间:2010-01-05 22:54:34

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

我目前正在尝试通过MVC验证,并且遇到了一些需要字段的问题,具体取决于另一个字段的值。下面是一个例子(我还没想到) - 如果PaymentMethod ==“Check”,那么应该需要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; }

我正在使用[Required]的System.ComponentModel.DataAnnotations,并且还扩展了ValidationAttribute以尝试使其工作,但我无法通过变量来进行验证(下面的扩展名)< / p>

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 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:4)

只需使用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验证。

答案 2 :(得分: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,但这只能处理这种逻辑。甚至稍微复杂一点的东西还需要另一个非常特殊的属性,等等会很快变得疯狂。

答案 3 :(得分:2)

使用conditional validation attribute例如

可以相对简单地解决您的问题
[RequiredIf("PaymentMethod == 'Cheque'")]
public string ChequeName { get; set; }