I'm using FluentValidation for server validation and one of the validation uses a custom extension method with a parameter. Said method is going to require a few more parameters from the root object (entity).
Currently the code is:
RuleFor(entity => entity.A).CustomExtension("test")
...
public static IRuleBuilder<T, string> CustomExtension<T>(this IRuleBuilder<T, string> builder, string someValue){
I need to change this so that...
RuleFor(entity => entity.A).CustomExtension(entity.PropertyB) //<- basically need to pass a entity property as variable
public static IRuleBuilder<T, string> CustomExtension<T>(this IRuleBuilder<T, string> builder, string propertyA){
}
Greatly appreciate any help!
You don't have access to the instance to validate during construction of the validator. There are probably a few ways to do it which may depend on what type of rule you're trying to implement.
The two ways I am thinking of is utilizing existing custom validators that provide the instance to validate (directly or via context). The former gives you just that, the instance passed to the validator, the latter additionally gives you a context which you can use to provide data to the validator at run time.
Let's assume you can use the Must extension to create your custom validator which means we're looking at the former case. Must has a few overloads, one of which provides the instance being validated as part of a Func lambda. The following LINQPad example shows how you can leverage this to create your own extension:
void Main()
{
var validator = new MyValidator();
var myEntity1 = new MyEntity();
myEntity1.A = Guid.NewGuid();
myEntity1.B = myEntity1.A;
var validateResult1 = validator.Validate(myEntity1);
Console.WriteLine("Expected result: no errors");
Console.WriteLine(validateResult1.Errors.Select(x => x.ErrorMessage));
var myEntity2 = new MyEntity();
myEntity2.A = Guid.NewGuid();
myEntity2.B = Guid.NewGuid();
var validateResult2 = validator.Validate(myEntity2);
Console.WriteLine("Expected result: 3 errors");
Console.WriteLine(validateResult2.Errors.Select(x => x.ErrorMessage));
}
public class MyEntity
{
public Guid A { get; set; }
public Guid B { get; set; }
}
public class MyValidator : AbstractValidator<MyEntity>
{
public MyValidator()
{
RuleFor(x => x.A).Equal(x => x.B).WithMessage("Error via equal");
RuleFor(x => x.A).Must((myEntityInstance, valueOfA) => myEntityInstance.B.Equals(valueOfA)).WithMessage("Error via normal must");
RuleFor(x => x.A).CustomExtension(x => x.B).WithMessage("Error via custom extension");
}
}
public static class Extensions
{
public static IRuleBuilderOptions<T, TProperty> CustomExtension<T, TProperty, TCompareTo>
(this IRuleBuilder<T, TProperty> ruleBuilder, Func<T, TCompareTo> propertyToCompareTo)
{
return ruleBuilder.Must((myEntityInstance, valueOfA) => propertyToCompareTo(myEntityInstance).Equals(valueOfA));
}
}
Result:
This is a bit contrived in the absence of knowing what your custom extension is going to do, but it does demonstrate one way of getting hold of the instance to validate at run time in your own extension.