Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3298
  • Last Modified:

ASP.Net MVC 4 C# -- conditional Model validation ?

I have one app, but each car/truck has different
"WORK_ORDER" database table requirements.

How can I setup WORK_ORDER.cs conditional validation
since some controllers have different "REQUIRED fields" ?
--------------------------------------------------
WORK_ORDER.cs CURRENT
  ** [Required(ErrorMessage = "Supplier is required")]
     public string Supplier { get; set; }

WORK_ORDER.cs DESIRED
  ** if "car/truck" field is BUICK, then
     [Required(ErrorMessage = "Supplier is required")]
     public string Supplier { get; set; }
  ** else
     public string Supplier { get; set; }
--------------------------------------------------
Example
1. create a new \Controllers\BUICK_HeaderController.cs
2. system automatically creates \Views\BUICK_Header\Create.cshtml, Delete.cshtml, etc
3. repeat steps for OtherCars_DetailController.cs, OtherTrucks_DetailController.cs, etc
4. setup WORK_ORDER.cs conditional validation since
   some controllers have different "REQUIRED fields"
0
finance_teacher
Asked:
finance_teacher
1 Solution
 
StephanLead Software EngineerCommented:
Hi, You probably need to create a new type of attributes that specifies your condition.

Here is version I mostly use:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
    public class RequiredIfAttribute : ConditionalAttributeBase, IClientValidatable
    {
        private RequiredAttribute _innerAttribute = new RequiredAttribute();

        public string DependentProperty { get; set; }
        public object TargetValue { get; set; }

        public RequiredIfAttribute(string dependentProperty, object targetValue)
            : this(dependentProperty, targetValue, null)
        {
        }

        public RequiredIfAttribute(string dependentProperty, object targetValue, string errorMessage)
            : base(errorMessage)
        {
            this.DependentProperty = dependentProperty;
            this.TargetValue = targetValue;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (ShouldRunValidation(value, this.DependentProperty, this.TargetValue, validationContext))
            {
                if (!_innerAttribute.IsValid(value))
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName), 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);

            string targetValue = (this.TargetValue ?? "").ToString();
            if (this.TargetValue != null && 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)
        {
            return QualifyFieldId(metadata, this.DependentProperty, viewContext);
        }

        public override string FormatErrorMessage(string name)
        {
            if (!String.IsNullOrEmpty(this.ErrorMessageString))
                _innerAttribute.ErrorMessage = this.ErrorMessageString;
            return _innerAttribute.FormatErrorMessage(name);
        }
    }

Open in new window


It would be nice to add some client-side validation as well,
copy this code and place it after the unobstrusive validation script is loaded:
(function ($) {
    $.validator.addMethod('requiredif',
        function (value, element, parameters) {
            var id = '#' + parameters['dependentproperty'];
            var targetvalue = parameters['targetvalue'];
            targetvalue =
              (targetvalue == null ? '' : targetvalue).toString();
            var control = $(id);
            var controltype = control.attr('type');
            var actualvalue =
                controltype === 'checkbox' ?
                control.attr('checked').toString() :
                control.val();

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

Open in new window


Then it is possible to use it like this:
[RequiredIf("TransportType", "BUICK", ErrorMessage = "Supplier is required")]
public string Supplier { get; set; }
0
 
Mihai StancescuSoftware Engineer Commented:
Hi,

You can also use the IValidatableObject interface to provide model code validation.

Here is an example and more information IValidatableObject.


Regards,
Mishu
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now