1

I have a model with properties that look like this:

public class YourDetails {

  [Required(ErrorMessage = "Code is required")]
  [StringLength(10, ErrorMessage = "Code length is wrong", MinimumLength = 2)]
  [Range(0, int.MaxValue, ErrorMessage = "Please enter a value bigger than {1}")]
  public int Code { get; set; }

}

The UI validation is setup the usual out of the box way with unobtrusive JS validation plugin.

The issue: I have 2 navigation actions, back and next. Next is fine, validation fires when things are wrong, and when things are right i.e. .isValid() returns true, the data is passed to the DB service etc etc.

However when I press 'back' I have a requirement to validate the form/ViewModel differently prior to saving. I.e. make sure Code is a positive integer, but don't bother with the Required or StringLength validation.

So basically I want to validate fully on Next but partially on Back. Is that possible?

2 Answers 2

1

When I've done something similar in the past the easiest way i found was to use fluent validation http://fluentvalidation.codeplex.com/wikipage?title=mvc. You can pass parameters to the validator and switch to different rule sets.

Sign up to request clarification or add additional context in comments.

1 Comment

I think this is the best approach. Seems that with Fluent you can hook into the client side JS validation and choose what to validate when. Nice. Thanks.
0

I've used the following conditional "Required" & "StringLength" attributes in the past and they work well.

Required If Attribute:

using System;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

namespace Website.Core.Mvc.DataAnnotations
{
    [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true)]
    public class RequiredIfAttribute : RequiredAttribute
    {
        public string OtherProperty { get; set; }

        public object OtherPropertyValue { get; set; }

        public RequiredIfAttribute(string otherProperty, object value)
            : base()
        {
            OtherProperty = otherProperty;
            OtherPropertyValue = value;
        }

        private object _TypeId = new object();

        public override object TypeId
        {
            get
            {
                return _TypeId;
            }
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            PropertyInfo property = validationContext.ObjectType.GetProperty(this.OtherProperty);
            if (property == null)
            {
                return new ValidationResult(this.OtherProperty + " not found");
            }

            // Get 
            object actualOtherPropertyValue = property.GetValue(validationContext.ObjectInstance, null);

            // If the other property matches the expected value then validate as normal
            if (IsRequired(OtherPropertyValue, actualOtherPropertyValue))
            {
                // Call base and validate required as normal
                ValidationResult isValid = base.IsValid(value, validationContext);
                return isValid;
            }
            return ValidationResult.Success;
        }

        protected virtual bool IsRequired(object otherPropertyValue, object actualOtherPropertyValue)
        {
            return object.Equals(OtherPropertyValue, actualOtherPropertyValue);
        }
    }
}

String Length If Attribute:

using System.ComponentModel.DataAnnotations;
using System.Reflection;

namespace Website.Core.Mvc.DataAnnotations
{
    public class StringLengthIfAttribute : StringLengthAttribute
    {
        public string OtherProperty { get; set; }

        public object OtherPropertyValue { get; set; }

        public StringLengthIfAttribute(int maximumLength, string otherProperty, object value)
            : base(maximumLength)
        {
            OtherProperty = otherProperty;
            OtherPropertyValue = value;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            PropertyInfo property = validationContext.ObjectType.GetProperty(this.OtherProperty);
            if (property == null)
            {
                return new ValidationResult(this.OtherProperty + " not found");
            }

            // Get 
            object actualOtherPropertyValue = property.GetValue(validationContext.ObjectInstance, null);

            // If the other property matches the expected value then validate as normal
            if (object.Equals(OtherPropertyValue, actualOtherPropertyValue))
            {
                // Call base and validate required as normal
                return base.IsValid(value, validationContext);
            }
            return null;
        }
    }
}

Example Usage:

public class MyModel
{
    [RequiredIf("IsBack", false)]
    public string Name { get; set; }

    public bool IsBack { get; set; } 
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.