In the previous posts, I’ve presented some basic info and possible configuration. Now, it’s time to show more complex examples.

Custom Validator

Sometimes build-in validator may not be enough. Then, you need to create it on your own. To have custom validator you define a class that inherits from PropertyValidator. We can pass the validation message to the base class. Moreover, our validation should be written inside IsValid the method.

public class GuidFormatValidator : PropertyValidator
{
  public GuidFormatValidator() : base("Property {PropertyName} has invalid Guid format")
  {
  }

  protected override bool IsValid(PropertyValidatorContext context)
  {
    var value = (string) context.PropertyValue;
    Guid guid;
    return Guid.TryParse(value, out guid);
  }
}

When property validator is ready, we can use it. To achieve that, when defining the rule for the property we just use SetValidator method and pass already created validator.

RuleFor(e => e.GuidAsString)
  .SetValidator(new GuidFormatValidator());

Dependent and conditional rules

Next element I’m going to explain is chaining validation of different properties. We can use DependentRules that will call given rules only if the previous one is valid. Let’s say that we have class Vehicle with the vehicle type and wheels count.

public enum VehicleType
{
  Motorbike,
  Car
}

public class Vehicle
{
  public VehicleType Type { get; set; }
  public int Wheels { get; set; }
}

Next, we want to check wheels count only if the vehicle type is correct. So, we add rules as follows:

RuleFor(v => v.Type)
  .IsInEnum()
  .DependentRules(() =>
  {
    RuleFor(v => v.Wheels)
      .NotEmpty();
  });

Another possible option is to call rules conditionally. For the previous object, we can check wheels based on one of the defined types.

When(x => x.Type == VehicleType.Motorbike, () =>
{
  RuleFor(x => x.Wheels)
    .Equal(2);
}).Otherwise(() =>
{
  RuleFor(x => x.Wheels)
    .Equal(4);
});

Include rule

At first define class Parent and derived class Child.

public class Parent
{
  public string Name { get; set; }
}

public class Child : Parent
{
}

Next, we define two validators. In this case one for the base and second for subclass which includes the first validator.

public class ParentValidator : AbstractValidator<Parent>
{
  public ParentValidator()
  {
    RuleFor(x => x.Name)
      .NotEmpty();
  }
}

public class ChildValidator : AbstractValidator<Child>
{
  public ChildValidator()
  {
    Include(new ParentValidator());
  }
}

Another key point is that you should remember that Include can be only used for same types only. Then using ChildValidator we will get result described in ParentValidator:

'Name' must not be empty.

In the next post, I’ll show some examples of how to write tests for your validation rules.