Search code examples
c#unobtrusive-validationasp.net-core-5.0requiredfieldvalidatormodelstate

Custom RequiredIfAttribute not producing error message on ModelState.IsValid check


I have a custom required if attribute which I am using to validate a dropdownlist based on whether values are selected in another dropdownlist.

The code below is what the custom attribute is currently using:

public class RequiredIfAttribute : ValidationAttribute
    {
        private const string DefaultErrorMessageFormatString = "The {0} field is required.";
        private readonly string[] _dependentProperties;
        
        public RequiredIfAttribute(string[] dependentProperties)
        {
            _dependentProperties = dependentProperties;
            ErrorMessage = DefaultErrorMessageFormatString;
        }
        
        private bool IsValueRequired(string checkValue, Object currentValue)
        {
            if (checkValue.Equals("!null", StringComparison.InvariantCultureIgnoreCase))
            {
                return currentValue != null;
            }

            return checkValue.Equals(currentValue);
        }
        
        protected override ValidationResult IsValid(Object value, ValidationContext context)
        {
            Object instance = context.ObjectInstance;
            Type type = instance.GetType();
            bool valueRequired = false;

            foreach (string s in _dependentProperties)
            {
                var fieldValue = s.Split(',').ToList().Select(k => k.Trim()).ToArray();

                Object propertyValue = type.GetProperty(fieldValue[0]).GetValue(instance, null);

                valueRequired = IsValueRequired(fieldValue[1], propertyValue);
            }

            if (valueRequired)
            {
                return value != null
                    ? ValidationResult.Success
                    : new ValidationResult(context.DisplayName + " required. ");
            }
            return ValidationResult.Success;
        }
    }

I have the attribute currently defined in the model like this:

[RequiredIf(new[] {"OrganisationType,1", "OrganisationType, 9", "OrganisationType, 10"})]

First value is the dependent dropdownlist and the second is the Id from said dropdownlist that has to be selected for the value of the other dropdownlist to be required.

The code below shows how the RequiredIf is bound to its respective value:

public SelectList SubOrganisationTypeList { get; set; }
        
        [Display(Name = "Sub organisation type")]
        
        [RequiredIf(new[] {"OrganisationType,1", "OrganisationType, 9", "OrganisationType, 10"})]
        public int SubOrganisationType { get; set; }

Currently when I submit the form that this custom attribute is used on it passes the ModelState.IsValid check, the unobtrusive validation I use also does not catch this.

How do I go about making sure that the error is caught by the ModelState.IsValid check as well as getting unobtrusive validation to fire when a value is not selected if one of values is selected in the dependent dropdownlist?


Solution

  • In the end it was actually a very simple fix I had set the default value of the sub dropdownlist to 0 as shown below:

     SelectListItem defaultItem = new SelectListItem();
                defaultItem.Value = "0";
                defaultItem.Text = "Sub organisation type...";
                items.Add(defaultItem);
    

    This was causing both the client and server side validation to validate the selection as true.

    In order to fix I removed the default of 0 to an empty string again this change is shown below:

     SelectListItem defaultItem = new SelectListItem();
                defaultItem.Value = "";
                defaultItem.Text = "Sub organisation type...";
                items.Add(defaultItem);