1

I have a second thing:

<td>
    @Html.LabelFor(m => m.Number, titleHtmlAttrs)
</td>
<td>
    <span class="element-value2">
        @Html.EditorFor(m => m.Number)
        @Html.ValidationTooltipFor(m => m.Number)
    </span>
</td>

And this is how this field looks like in model:

[Display(Name = "Special Number")]
[StringLength(20)]
public string Number { get; set; }

Which means that if I wanted to change this field, i can have any value from empty to 20. It's ok, but now I need an additional validation. In model I have some fields:

public DateTime? TimeOf { get; set; }
public bool HasType { get; set; }

New validation should work ONLY if TimeOf is not null and HasType is true. New validation should prevent empty values in Number. Basically, change (from empty to 20) to (from 1 to 20).

How could I correctly accomplish this?

P.S Sorry about my bad English.

Olegs Jasjko
  • 2,128
  • 6
  • 27
  • 47
  • Look at the [foolproof](http://foolproof.codeplex.com/) `[RequiredIfTrue]` and `[RequiredIfNotEmpty]` validation attributes –  Dec 16 '14 at 07:14

2 Answers2

2

For complex validation logic, look at implementing IValidatableObject in your ViewModel and then you can place your conditional validation logic inside the Validate method. (Caveat, this is obviously server side)

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (this.HasType)
    {
       // Do other conditional validation
       if (validationFails)
       {
           yield return new ValidationResult("descriptive error goes here");
       }
    } 
    // Other validation here.
Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
0

UPDATE It seems I have misunderstood the question. As the other answer has already pointed out, you could implement the IValidatableObject for achieving this. Something like:

public class YourModelName : IValidatableObject
{
  [StringLength(20)]
  public string Number{ get; set; }

  [Required]
  public DateTime? TimeOf { get; set; }

  public bool HasType { get; set; }

  public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
  { 
    var results = new List<ValidationResult>();

    if (TimeOf != null && HasType)
       Validator.TryValidateProperty(this.Number,
            new ValidationContext(this, null, null) { MemberName = "Number" },
            results);    

    if (TimeOf == null) 
       results.Add(new ValidationResult("Date Time must have a value"));
    if (!HasType)
       results.Add(new ValidationResult("Must be true"));

    return results;
  }

}

OLD ANSWER: You could write your custom validator for more complex validation conditions. Something like:

public class SomeCustomValidator : ValidationAttribute
{
   protected override ValidationResult IsValid(object value, ValidationContext validationContext)
   {
      string number = value as string;
      if (value == null) throw new InvalidOperationException("Can only be used on string properties");

      if (!value.IsEmpty && value.Length <= 20)
      {
          return ValidationResult.Success;
      }

      return new ValidationResult("Name must be a non-empty string smaller than 20 chars"));
   }
}

And for HasType, another custom one:

public class IsTrueAttribute : ValidationAttribute
{

  public override bool IsValid(object value)
  {
      if (value == null) return false;
      if (value.GetType() != typeof(bool)) throw new InvalidOperationException("can only be used on boolean properties.");

      return (bool) value == true;
  }

}

And on TimeOf you could use the required attribute to make sure it has a value:

[Required(ErrorMessage="Must have value")]
public DateTime? TimeOf {get;set;}

And use the custom attributes on the other two:

[SomeCustomValidator(ErrorMessage="Error msg...")]
public string Number {get;set;}

[IsTrueAttribute(ErrorMessage="Must be true")]
public bool HasType {get;set;}
barca_d
  • 1,031
  • 2
  • 13
  • 30
  • You have misunderstood the question. OP wants `Number` to be required based on the value of the other properties. And your `SomeCustomValidator` does exactly what `[StringLength]` does but without client side validation –  Dec 16 '14 at 07:53