RequiredIf Conditional Validation Attribute

后端 未结 6 1168
长发绾君心
长发绾君心 2020-11-22 15:19

I was looking for some advice on the best way to go about implementing a validation attribute that does the following.

Model

public class MyInputMode         


        
6条回答
  •  庸人自扰
    2020-11-22 15:53

    I got it to work on ASP.NET MVC 5

    I saw many people interested in and suffering from this code and i know it's really confusing and disrupting for the first time.

    Notes

    • worked on MVC 5 on both server and client side :D
    • I didn't install "ExpressiveAnnotations" library at all.
    • I'm taking about the Original code from "@Dan Hunex", Find him above

    Tips To Fix This Error

    "The type System.Web.Mvc.RequiredAttributeAdapter must have a public constructor which accepts three parameters of types System.Web.Mvc.ModelMetadata, System.Web.Mvc.ControllerContext, and ExpressiveAnnotations.Attributes.RequiredIfAttribute Parameter name: adapterType"

    Tip #1: make sure that you're inheriting from 'ValidationAttribute' not from 'RequiredAttribute'

     public class RequiredIfAttribute : ValidationAttribute, IClientValidatable { ...}
    

    Tip #2: OR remove this entire line from 'Global.asax', It is not needed at all in the newer version of the code (after edit by @Dan_Hunex), and yes this line was a must in the old version ...

    DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequiredAttributeAdapter));
    

    Tips To Get The Javascript Code Part Work

    1- put the code in a new js file (ex:requiredIfValidator.js)

    2- warp the code inside a $(document).ready(function(){........});

    3- include our js file after including the JQuery validation libraries, So it look like this now :

    @Scripts.Render("~/bundles/jqueryval")
    
    

    4- Edit the C# code

    from

    rule.ValidationParameters["dependentproperty"] = (context as ViewContext).ViewData.TemplateInfo.GetFullHtmlFieldId(PropertyName);
    

    to

    rule.ValidationParameters["dependentproperty"] = PropertyName;
    

    and from

    if (dependentValue.ToString() == DesiredValue.ToString())
    

    to

    if (dependentValue != null && dependentValue.ToString() == DesiredValue.ToString())
    

    My Entire Code Up and Running

    Global.asax

    Nothing to add here, keep it clean

    requiredIfValidator.js

    create this file in ~/content or in ~/scripts folder

        $.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'desiredvalue'], function (options)
    {
        options.rules['requiredif'] = options.params;
        options.messages['requiredif'] = options.message;
    });
    
    
    $(document).ready(function ()
    {
    
        $.validator.addMethod('requiredif', function (value, element, parameters) {
            var desiredvalue = parameters.desiredvalue;
            desiredvalue = (desiredvalue == null ? '' : desiredvalue).toString();
            var controlType = $("input[id$='" + parameters.dependentproperty + "']").attr("type");
            var actualvalue = {}
            if (controlType == "checkbox" || controlType == "radio") {
                var control = $("input[id$='" + parameters.dependentproperty + "']:checked");
                actualvalue = control.val();
            } else {
                actualvalue = $("#" + parameters.dependentproperty).val();
            }
            if ($.trim(desiredvalue).toLowerCase() === $.trim(actualvalue).toLocaleLowerCase()) {
                var isValid = $.validator.methods.required.call(this, value, element, parameters);
                return isValid;
            }
            return true;
        });
    });
    

    _Layout.cshtml or the View

    @Scripts.Render("~/bundles/jqueryval")
    
    

    RequiredIfAttribute.cs Class

    create it some where in your project, For example in ~/models/customValidation/

        using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Web.Mvc;
    
    namespace Your_Project_Name.Models.CustomValidation
    {
        public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
        {
            private String PropertyName { get; set; }
            private Object DesiredValue { get; set; }
            private readonly RequiredAttribute _innerAttribute;
    
            public RequiredIfAttribute(String propertyName, Object desiredvalue)
            {
                PropertyName = propertyName;
                DesiredValue = desiredvalue;
                _innerAttribute = new RequiredAttribute();
            }
    
            protected override ValidationResult IsValid(object value, ValidationContext context)
            {
                var dependentValue = context.ObjectInstance.GetType().GetProperty(PropertyName).GetValue(context.ObjectInstance, null);
    
                if (dependentValue != null && dependentValue.ToString() == DesiredValue.ToString())
                {
                    if (!_innerAttribute.IsValid(value))
                    {
                        return new ValidationResult(FormatErrorMessage(context.DisplayName), new[] { context.MemberName });
                    }
                }
                return ValidationResult.Success;
            }
    
            public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
            {
                var rule = new ModelClientValidationRule
                {
                    ErrorMessage = ErrorMessageString,
                    ValidationType = "requiredif",
                };
                rule.ValidationParameters["dependentproperty"] = PropertyName;
                rule.ValidationParameters["desiredvalue"] = DesiredValue is bool ? DesiredValue.ToString().ToLower() : DesiredValue;
    
                yield return rule;
            }
        }
    }
    

    The Model

        using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web;
    using Your_Project_Name.Models.CustomValidation;
    
    namespace Your_Project_Name.Models.ViewModels
    {
    
        public class CreateOpenActivity
        {
            public Nullable ORG_BY_CD { get; set; }
    
            [RequiredIf("ORG_BY_CD", "5", ErrorMessage = "Coordinator ID is required")] // This means: IF 'ORG_BY_CD' is equal 5 (for the example)  > make 'COR_CI_ID_NUM' required and apply its all validation / data annotations
            [RegularExpression("[0-9]+", ErrorMessage = "Enter Numbers Only")]
            [MaxLength(9, ErrorMessage = "Enter a valid ID Number")]
            [MinLength(9, ErrorMessage = "Enter a valid ID Number")]
            public string COR_CI_ID_NUM { get; set; }
        }
    }
    

    The View

    Nothing to note here actually ...

        @model Your_Project_Name.Models.ViewModels.CreateOpenActivity
    @{
        ViewBag.Title = "Testing";
    }
    
    @using (Html.BeginForm()) 
    {
        @Html.AntiForgeryToken()
    
        

    CreateOpenActivity


    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    @Html.LabelFor(model => model.ORG_BY_CD, htmlAttributes: new { @class = "control-label col-md-2" })
    @Html.EditorFor(model => model.ORG_BY_CD, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.ORG_BY_CD, "", new { @class = "text-danger" })
    @Html.LabelFor(model => model.COR_CI_ID_NUM, htmlAttributes: new { @class = "control-label col-md-2" })
    @Html.EditorFor(model => model.COR_CI_ID_NUM, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.COR_CI_ID_NUM, "", new { @class = "text-danger" })
    }

    I may upload a project sample for this later ...

    Hope this was helpful

    Thank You

提交回复
热议问题