【问题标题】:MVC RequiredIf Attribute - IsValid value parameter always nullMVC RequiredIf 属性 - IsValid 值参数始终为空
【发布时间】:2014-06-03 17:12:46
【问题描述】:

我正在实现一个 RequiredIf 验证属性,并且传递给 IsValid 方法的值始终为 null。

RequiredIfAttribute 类

    public class RequiredIfAttribute : ValidationAttribute
{
    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;
    }

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

视图模型

        [Required]
    [Display(Name = "Are You A Student?")]
    public bool? IsStudent { get; set; }

    [RequiredIf("IsStudent", true, ErrorMessage = "You must upload a photo of your student ID if you wish to register as a student.")]
    [Display(Name = "Student ID")]
    [FileExtensions("jpg|jpeg|png|pdf", ErrorMessage = "File is not in the correct format.")]
    [MaxFileSize(2 * 1024 * 1024, ErrorMessage = "You may not upload files larger than 2 MB.")]
    public HttpPostedFileBase StudentId { get; set; }

编辑器模板

    @model bool?
@using System.Web.Mvc;
@{
    var options = new List<SelectListItem>
    {
        new SelectListItem { Text = "Yes", Value = "true", Selected =  Model.HasValue && Model.Value },
        new SelectListItem { Text = "No", Value = "false", Selected =  Model.HasValue && Model.Value }
    };

    string defaultOption = null;

    if (ViewData.ModelMetadata.IsNullableValueType)
    {
        defaultOption = "(Select)";
    }
}

@Html.DropDownListFor(m => m, options, defaultOption)

每次提交表单时,都会抛出RequiredIf 错误消息,我感觉它与我最初描述的空值有关。我究竟做错了什么?谢谢!

注意:HTML 似乎可以正确呈现,所以我认为这不是问题。

    <select data-val="true" data-val-required="The Are You A Student? field is required." id="IsStudent" name="IsStudent"><option value="">(Select)</option>
<option value="true">Yes</option>
<option value="false">No</option>
</select>

【问题讨论】:

    标签: asp.net-mvc-4 data-annotations validationattribute


    【解决方案1】:

    因为这是你的代码 -

    public class RequiredIfAttribute : ValidationAttribute
    {
        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;
        }
    
        public override bool IsValid(object value)
        {
            return innerAttribute.IsValid(value);
        }
    }
    

    您使用的是RequriedAtrribute。因此,要模拟它的行为RequiredIf,您必须实现一些逻辑来检查目标属性值是真还是假。但你并没有这样做,只是从内在属性返回。所以它只是一个Required 而不是RequiredIf -

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

    修改这个函数来做一些检查,比如 -

    public override bool IsValid(object value)
    {
        //if the referred property is true then
            return innerAttribute.IsValid(value);
        //else
        return True
    }
    

    【讨论】:

    • 谢谢,但我的代码可以与其他字段一起使用,所以我认为您使用该解决方案是在寻找错误的树。这似乎与该字段可以为空或可以为空并使用下拉菜单作为选择机制这一事实有关。
    • @DomRocco 你找错树了。 Brainless Coder 100% 正确。
    【解决方案2】:

    我使用以下代码:

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
    public abstract class StefAttribute : ValidationAttribute
    {
        public WDCIAttribute()
            : base()
        {
            this.ErrorMessageResourceType = typeof(GlobalResources);
        }
    }
    
    
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
    public class StefRequiredIfAttribute : StefAttribute
    {
        private RequiredAttribute innerAttribute = new RequiredAttribute();
        public string DependentProperty { get; set; }
        public object TargetValue { get; set; }
    
        public WDCIRequiredIfAttribute()
        {
        }
    
        public WDCIRequiredIfAttribute(string dependentProperty, object targetValue)
            : base()
        {
            this.DependentProperty = dependentProperty;
            this.TargetValue = targetValue;
        }
    
        public override bool IsValid(object value)
        {
            return innerAttribute.IsValid(value);
        }
    }
    
    public class RequiredIfValidator : DataAnnotationsModelValidator<StefRequiredIfAttribute>
    {
        public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, StefRequiredIfAttribute attribute)
            : base(metadata, context, attribute)
        {
        }
    
        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
                object value = field.GetValue(container, null);
    
                // compare the value against the target value
                if (IsEqual(value) || (value == null && Attribute.TargetValue == null))
                {
                    // match => means we should try validating this field
                    if (!Attribute.IsValid(Metadata.Model))
                    {
                        // validation failed - return an error
                        yield return new ModelValidationResult { Message = ErrorMessage };
                    }
                }
            }
        }
    
        private bool IsEqual(object dependentPropertyValue)
        {
            bool isEqual = false;
    
            if (Attribute.TargetValue != null && Attribute.TargetValue.GetType().IsArray)
            {
                foreach (object o in (Array)Attribute.TargetValue)
                {
                    isEqual = o.Equals(dependentPropertyValue);
                    if (isEqual)
                    {
                        break;
                    }
                }
            }
            else
            {
                if (Attribute.TargetValue != null)
                {
                    isEqual = Attribute.TargetValue.Equals(dependentPropertyValue);
                }
            }
    
            return isEqual;
        }
    }
    

    可以在模型中使用如下:

    public class PersonnelVM : EntityVM
    {
        // . . .
    
        [DisplayName("Name")]
        [StefRequiredIf("IndividualOrBulk", PersonnelType.Bulk, ErrorMessageResourceName = GlobalResourceLiterals.Name_Required)]
        public string Name { get; set; }
    
        [DisplayName("PersonnelType")]
        public PersonnelType IndividualOrBulk { get; set; }
    
        // . . .
    }
    

    【讨论】:

    • 我不打算用这个实现客户端验证,我们的服务器端验证属性有一个非常相似的实现。感谢您发帖,但我在这里没有看到解决方案。
    猜你喜欢
    • 1970-01-01
    • 2012-05-31
    • 1970-01-01
    • 2016-11-22
    • 2014-08-06
    • 2021-07-04
    • 2018-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多