0

大家好!我混淆了實現一段代碼,以在幾個案例中使用不同的必需字段(6)的模型在asp.net mvc 3中進行工作.net數據註釋。 我有一個模型:.Net數據註解和模型層次結構

public class OpportunityModel 
{ 
    public Guid OpportunityId { get; set; } 

    [Display(Name = "Value")] 
    [RegularExpression(@"^[-+]?\d{1,10}(\.\d{0,4})?$", ErrorMessage = "Must be a number")] 
    public decimal? ActualValue { get; set; } 

    [Display(Name = "Name")] 
    [Required(ErrorMessage = "Name is required")] 
    public string Name { get; set; } 
    public string Product { get; set; } 

    [Display(Name = "Estimated Date")] 
    public DateTime? EstimateDate { get; set; } 


    public bool? Sales6ixFallDown { get; set; } 


    [Display(Name = "Stage")] 
    public Stages Sales6ixStage { get; set; } 

    public DateTime? Sales6ixDateInBoard { get; set; } 

    public DateTime? Sales6ixDateInCurrentStage { get; set; } 

    public DateTime? Sales6ixNextAppointmentDate { get; set; } 

    [Display(Name = "Description")] 
    public string Description { get; set; } 

    public string Sales6ixNextAppointmentDescription { get; set; } 

    public int NewColumn { get; set; } 

    public Guid? CustomerId { get; set; } 

    public string CustomerName { get; set; } 
} 

我需要的是可能性動態改變需要封地在裏面。一些谷歌搜索後,這是不可能的,並想出使用模型繼承。我的意思是:我有這樣的基本模型:

public class BaseOpportunityModel 
{ 
    public Guid OpportunityId { get; set; } 

    public virtual decimal? ActualValue { get; set; } 
    public virtual string Name { get; set; } 

    public string Product { get; set; } 

    public DateTime? EstimateDate { get; set; } 

    public bool? Sales6ixFallDown { get; set; } 


    [Display(Name = "Stage")] 
    public Stages Sales6ixStage { get; set; } 

    public DateTime? Sales6ixDateInBoard { get; set; } 

    public DateTime? Sales6ixDateInCurrentStage { get; set; } 

    public DateTime? Sales6ixNextAppointmentDate { get; set; } 

    [Display(Name = "Description")] 
    public string Description { get; set; } 

    public string Sales6ixNextAppointmentDescription { get; set; } 

    public int NewColumn { get; set; } 

    public Guid? CustomerId { get; set; } 

    public string CustomerName { get; set; } 
} 

其中虛擬屬性是可能是或不是必填字段的屬性。然後,我從基地這樣一個派生的幾個型號:

public class OpportunityModel0: BaseOpportunityModel 
{ 
    [Display(Name = "Value")] 
    [Required(ErrorMessage = "Name is required")] 
    [RegularExpression(@"^[-+]?\d{1,10}(\.\d{0,4})?$", ErrorMessage = "Must be a number")] 
    public override decimal? ActualValue { get; set; } 

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

}

,然後我可以在視圖和控制器示範基地BaseOpportunityModel使用。但是我遇到以下問題:

  • 驗證使用BaseOpportunityModel中的註釋屬性並忽略派生模型中的屬性。

我該怎麼做?有人可以引導我走向正確的方向,還是可以幫助我解決這個問題?提前致謝。

回答

1

我想通過使用自定義的RequiredIfValidator來驗證模型的不同要求。所以現在我只有一個模型和一個視圖。下面是代碼,可能有人會發現它有用:

RequiredIfAttribute:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ComponentModel.DataAnnotations; 
using System.Web.Mvc; 

namespace Infrastructure.Extensions 
{ 
    public class RequiredIfAttribute : ValidationAttribute, IClientValidatable 
    { 
     private RequiredAttribute _innerAttribute = new RequiredAttribute(); 

     public string DependentProperty { get; set; } 
     public object TargetValue { get; set; } 

     public RequiredIfAttribute(string dependentProperty, object targetValue) 
     { 
      this.DependentProperty = dependentProperty; 
      this.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(this.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 && this.TargetValue == null) || 
        (dependentvalue != null && dependentvalue.Equals(this.TargetValue))) 
       { 
        // match => means we should try validating this field 
        if (!_innerAttribute.IsValid(value)) 
         // validation failed - return an error 
         return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName }); 
       } 
      } 

      return ValidationResult.Success; 
     } 

     public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
     { 
      var rule = new ModelClientValidationRule() 
      { 
       ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), 
       ValidationType = "requiredif", 
      }; 

      string depProp = BuildDependentPropertyId(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!) 
      string targetValue = (this.TargetValue ?? "").ToString(); 
      if (this.TargetValue.GetType() == typeof(bool)) 
       targetValue = targetValue.ToLower(); 

      rule.ValidationParameters.Add("dependentproperty", depProp); 
      rule.ValidationParameters.Add("targetvalue", targetValue); 

      yield return rule; 
     } 

     private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext) 
     { 
      // build the ID of the property 
      string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(this.DependentProperty); 
      // unfortunately this will have the name of the current field appended to the beginning, 
      // because the TemplateInfo's context has had this fieldname appended to it. Instead, we 
      // want to get the context as though it was one level higher (i.e. outside the current property, 
      // which is the containing object (our Person), and hence the same level as the dependent property. 
      var thisField = metadata.PropertyName + "_"; 
      if (depProp.StartsWith(thisField)) 
       // strip it off again 
       depProp = depProp.Substring(thisField.Length); 
      return depProp; 
     } 
    } 
} 



RequiredIfValidator

namespace Infrastructure.Extensions 
{ 
    public class RequiredIfValidator : DataAnnotationsModelValidator<RequiredIfAttribute> 
    { 
     public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute) 
      : base(metadata, context, attribute) 
     { 
     } 

     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
     { 
      return base.GetClientValidationRules(); 
     } 

     public override IEnumerable<ModelValidationResult> Validate(object container) 
     { 
      // get a reference to the property this validation depends upon 
      var field = Metadata.ContainerType.GetProperty(Attribute.DependentProperty); 

      if (field != null) 
      { 
       // get the value of the dependent property 
       var value = field.GetValue(container, null); 

       // compare the value against the target value 
       if ((value == null && Attribute.TargetValue == null) || 
        (value.Equals(Attribute.TargetValue))) 
       { 
        // match => means we should try validating this field 
        if (!Attribute.IsValid(Metadata.Model)) 
         // validation failed - return an error 
         yield return new ModelValidationResult { Message = ErrorMessage }; 
       } 
      } 
     } 
    } 
} 



客戶端驗證

/// <reference path="jquery-1.4.4-vsdoc.js" /> 
    /// <reference path="jquery.validate.unobtrusive.js" /> 

    $.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 
      // note - this probably needs to cater for more 
      // control types, e.g. radios 
      var control = $(id); 
      var controltype = control.attr('type'); 
      var actualvalue = 
       controltype === 'checkbox' ? 
       control.is(":checked").toString() : 
      //control.attr('checked').toString() : 
       control.val(); 

      actualvalue = actualvalue.toLocaleLowerCase(); 

      // 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; 
     } 
    ); 

    $.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; 
     }); 
1

這個技巧應該在mvc 3中工作,計算到THIS。一件可能成爲問題的事情是你的發佈行爲。您應該在後置操作中將您的繼承模型指定爲參數。

public ActionResult MyPostAction(OpportunityModel0 model) 

如果基礎模型是參數,驗證將不起作用。

+0

感謝您的答覆。另一件不起作用的是客戶端驗證。我可以通過在View OpportunityModel0中指定來修復它,但是我需要爲每個派生模型都有這樣的視圖。這不是一個好方法。 – Roman