2010-01-05 67 views
7

我目前正在嘗試通過MVC驗證,並且針對一些需要根據其他字段的值而需要的問題。下面是一個例子(我還沒有弄清楚) - 如果PaymentMethod ==「Check」,那麼ChequeName應該是必需的,否則它可以通過。Asp.Net MVC驗證 - 依賴字段

[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,並且還擴大一個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")] 

有沒有人有這種驗證的經驗?將它寫入控制器會更好嗎?

感謝您的幫助。

+0

第二個想法...您如何設置PaymentSelected = PaymentMethod?您應該收到錯誤,因爲PaymentMethod不是一個常量表達式。 – Min 2010-01-05 23:34:03

+0

嗨敏,你說得對。我認爲我可以這樣做,但它不起作用。我只是想展示我曾經嘗試過的,但也評論說它不會讓我通過這個變量。 – 2010-01-06 00:44:03

回答

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,但那隻能處理這種類型的邏輯。即使稍微複雜一些的東西也需要另一個非常具體的屬性,等等,它很快就會變得瘋狂。

+0

感謝djuth,我已經採用了ModelStateDictionary並在模型中對此進行了驗證,然後將字典傳遞迴控制器以合併到ModelState中。似乎要做的伎倆,並允許我做一些程序化的工作 - 只是做每個屬性的聲明不太好,但至少我可以在一個位置得到一切。不知道如果每個屬性都有多個錯誤,這將會如何。 – 2010-01-11 01:37:32

4

如果你想在除了客戶端驗證服務器上驗證模式,我覺得去最好的辦法就是自定義驗證屬性(如雅羅斯瓦夫建議)。我在這裏包括我使用的源代碼。

自定義屬性:

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; } 
+0

我意識到這個答案是2歲,但我試圖讓這個工作,基本上它激發了依賴屬性的驗證,不管第一個屬性的值是什麼。任何幫助,將不勝感激。 – 2015-04-23 01:05:12

3

只需使用萬無一失的驗證庫,在CodePlex上: https://foolproof.codeplex.com/

它支持以下「requiredif」確認屬性/裝飾品:

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

上手容易:

  1. 從所提供的鏈接
  2. 下載包的引用添加到包含.dll文件
  3. 導入包含的JavaScript文件
  4. 確保您的vi ews引用其HTML中包含的JavaScript文件,用於不引人注意的JavaScript和jQuery驗證。