【问题标题】:.Net Data annotation and model hierarchy.Net 数据注释和模型层次结构
【发布时间】:2012-09-23 02:12:28
【问题描述】:

大家!我对实现一段代码以在 asp.net mvc 3 中使用具有不同必填字段的模型(6)进行工作感到困惑。 我有一个模型:

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

}

然后我可以在 View 和 Controller 基础模型 BaseOpportunityModel 中使用。但是我遇到了以下问题:

  • 验证使用来自 BaseOpportunityModel 的注释属性并忽略派生模型中的属性。

我做错了什么?有人可以引导我朝着正确的方向前进或帮助我解决这个问题吗?提前致谢。

【问题讨论】:

    标签: .net asp.net-mvc-3 validation data-annotations model-validation


    【解决方案1】:

    我发现我的问题是使用自定义RequiredIfValidator 对模型进行不同的reqired 验证。所以现在我只有一个模型和一个视图。这是代码,可能有人觉得它有用:

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

    【讨论】:

      【解决方案2】:

      根据THIS,这个技巧应该可以在 mvc 3 中使用。可能有问题的一件事是您的发布操作。您应该在 post 操作中将继承的模型指定为参数。

      public ActionResult MyPostAction(OpportunityModel0 model)
      

      如果基本模型是参数,验证将不起作用。

      【讨论】:

      • 感谢您的回复。另一件不起作用的事情是客户端验证。我可以通过在 View OpportunityModel0 中指定来修复它,但是我需要为每个派生模型提供这样的视图。这不是一个好方法。
      猜你喜欢
      • 2015-01-26
      • 2018-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-02
      • 2016-05-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多