【问题标题】:attribute dependent on another field依赖于另一个字段的属性
【发布时间】:2010-09-14 22:07:16
【问题描述】:

在我的 ASP.NET MVC 应用程序模型中,我希望仅在选中特定复选框时才根据需要验证文本框。

类似

public bool retired {get, set};

[RequiredIf("retired",true)]
public string retirementAge {get, set};

我该怎么做?

谢谢。

【问题讨论】:

标签: asp.net-mvc validation model annotations


【解决方案1】:

看看这个:http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx

我已经修改了代码以满足我的需要。也许您也会从这些变化中受益。

public class RequiredIfAttribute : ValidationAttribute
{
    private RequiredAttribute innerAttribute = new RequiredAttribute();
    public string DependentUpon { get; set; }
    public object Value { get; set; }

    public RequiredIfAttribute(string dependentUpon, object value)
    {
        this.DependentUpon = dependentUpon;
        this.Value = value;
    }

    public RequiredIfAttribute(string dependentUpon)
    {
        this.DependentUpon = dependentUpon;
        this.Value = null;
    }

    public override bool IsValid(object value)
    {
        return innerAttribute.IsValid(value);
    }
}

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

    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        // no client validation - I might well blog about this soon!
        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.DependentUpon);

        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.Value == null) || (value != null && value.Equals(Attribute.Value)))
            {
                // match => means we should try validating this field
                if (!Attribute.IsValid(Metadata.Model))
                    // validation failed - return an error
                    yield return new ModelValidationResult { Message = ErrorMessage };
            }
        }
    }
}

然后使用它:

public DateTime? DeptDateTime { get; set; }
[RequiredIf("DeptDateTime")]
public string DeptAirline { get; set; }

【讨论】:

  • 你需要添加'DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequiredIfValidator));'到您的 global.asax.cs 以使其正常工作。 (如 RickardN 提供的链接中所述。
  • ModelMetadata.FromLambdaExpression(ex, html.ViewData).IsRequired 总是返回 false 即使依赖属性是真/假
  • // compare the value against the target value 之后的 if 应改为将 (value == null &amp;&amp; Attribute.Value == null) 作为条件的第一部分。 (将!= 更改为==
【解决方案2】:

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

除其他外,它支持以下“必需的”验证属性/装饰:

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

上手很简单:

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

【讨论】:

  • 链接?它似乎对我来说工作正常 - 我正在使用 EF 6。我下载了 Foolproof 的源代码并自己编译了它,所以也许这可以解释为什么它对我有用?
  • 我可以使用:[RequiredIfTrue] [RequiredIfFalse] - 在具有 2 个不同依赖属性的单个属性上使用吗?示例:[RequiredIfFalse("IsQuote", ErrorMessage = @"Provider must be enter.")] [ RequiredIfTrue("IsIfa", ErrorMessage = @"必须输入Provider。")] [XmlElement("Provider", IsNullable = true)] public string Provider { get;放; }
  • 很可能。我的建议是进行更改,然后对其运行单元测试以查看其是否按预期工作。
【解决方案3】:

我使用 NuGet 包管理器安装了这个:https://github.com/jwaliszko/ExpressiveAnnotations

这是我的模型:

using ExpressiveAnnotations.Attributes;

public bool HasReferenceToNotIncludedFile { get; set; }

[RequiredIf("HasReferenceToNotIncludedFile == true", ErrorMessage = "RelevantAuditOpinionNumbers are required.")]
public string RelevantAuditOpinionNumbers { get; set; }

我向你保证这会奏效!

【讨论】:

    【解决方案4】:

    我没有看到任何开箱即用的东西可以让你这样做。

    我已经创建了一个类供您使用,它有点粗糙,而且绝对不灵活..但我认为它可能会解决您当前的问题。或者至少让你走上正轨。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.ComponentModel.DataAnnotations;
    using System.Globalization;
    
    namespace System.ComponentModel.DataAnnotations
    {
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
        public sealed class RequiredIfAttribute : ValidationAttribute
        {
            private const string _defaultErrorMessage = "'{0}' is required";
            private readonly object _typeId = new object();
    
            private string  _requiredProperty;
            private string  _targetProperty;
            private bool    _targetPropertyCondition;
    
            public RequiredIfAttribute(string requiredProperty, string targetProperty, bool targetPropertyCondition)
                : base(_defaultErrorMessage)
            {
                this._requiredProperty          = requiredProperty;
                this._targetProperty            = targetProperty;
                this._targetPropertyCondition   = targetPropertyCondition;
            }
    
            public override object TypeId
            {
                get
                {
                    return _typeId;
                }
            }
    
            public override string FormatErrorMessage(string name)
            {
                return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, _requiredProperty, _targetProperty, _targetPropertyCondition);
            }
    
            public override bool IsValid(object value)
            {
                bool result             = false;
                bool propertyRequired   = false; // Flag to check if the required property is required.
    
                PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
                string requiredPropertyValue            = (string) properties.Find(_requiredProperty, true).GetValue(value);
                bool targetPropertyValue                = (bool) properties.Find(_targetProperty, true).GetValue(value);
    
                if (targetPropertyValue == _targetPropertyCondition)
                {
                    propertyRequired = true;
                }
    
                if (propertyRequired)
                {
                    //check the required property value is not null
                    if (requiredPropertyValue != null)
                    {
                        result = true;
                    }
                }
                else
                {
                    //property is not required
                    result = true;
                }
    
                return result;
            }
        }
    }
    

    在您的模型类之上,您应该只需要添加:

    [RequiredIf("retirementAge", "retired", true)]
    public class MyModel
    

    在你看来

    <%= Html.ValidationSummary() %> 
    

    当已停用的属性为真且所需的属性为空时,应显示错误消息。

    希望这会有所帮助。

    【讨论】:

      【解决方案5】:

      试试我的自定义validation attribute

      [ConditionalRequired("retired==true")]
      public string retirementAge {get, set};
      

      支持多种条件。

      【讨论】:

      • 如果您可以在您的存储库中提供一个完整的项目,其中包括所有必需的引用,例如 System.Linq.Dynamic,那就太好了。此外,您似乎正在使用 System.Linq.Dynamic 的自定义版本,因为 Microsoft 有一个采用 1 个参数的 ExpressionParser.Parse() 方法,但您调用的是 2 个参数版本。
      • 感谢@IanKemp,我会考虑您的建议并改进存储库
      • @karaxuna 我该怎么办 ExpressionParser 有一个错误显示我?
      猜你喜欢
      • 2014-11-30
      • 1970-01-01
      • 2020-05-17
      • 1970-01-01
      • 1970-01-01
      • 2016-12-18
      • 2020-10-19
      • 2015-09-15
      • 2019-02-16
      相关资源
      最近更新 更多