Liens
Exemple
|
var mc = new MyClass();
var validator = new MyClassValidator();
ValidationResult results = validator.Validate(mc);
if (!results.IsValid)
{
foreach (var failure in results.Errors)
{
Console.WriteLine("Property " + failure.PropertyName + " failed validation. Error was: " +
failure.ErrorMessage);
}
string allMessages = results.ToString();
Console.WriteLine(allMessages);
}
public sealed class MyClassValidator : AbstractValidator<MyClass>
{
public MyClassValidator()
{
this.RuleFor(x => x.Name)
.NotNull()
.Must(name => name != null)
.Must(IsValid)
.WithMessage("Name is invalid."); // change error message. Default is: 'Name' must not be empty.
}
private static bool IsValid(string value)
{
return value != null;
}
}
public sealed class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
}
|
|
public sealed class MyClassValidator : AbstractValidator<MyClass> {
public MyClassValidator() {
RuleFor(mc => mc.MySubClass).SetValidator(new MySubClassValidator());
}
}
public sealed class MySubClassValidator : AbstractValidator<MySubClass> {
public MySubClassValidator() {
RuleFor(msc => msc.Name).NotNull();
}
}
public sealed class MyClass
{
public int Id { get; set; }
public MySubClass MySubClass { get; set; }
}
public sealed class MySubClass
{
public int Id { get; set; }
public string Name { get; set; }
}
|
|
public sealed class MyClassValidator : AbstractValidator<MyClass> {
public MyClassValidator() {
// use RuleForEach to apply rules on each element
RuleForEach(x => x.Items)
.NotEmpty()
// use ChildRules for complex object
.ChildRules(items =>
{
items.RuleFor(x => x.Name).NotNull();
});
RuleForEach(mc => mc.Items)
.SetValidator(new ItemValidator());
// use ForEach inside a RuleFor to apply rules on each element
RuleFor(x => x.Ids)
.NotEmpty()
.ForEach(idRule => idRule.Must(x => x > 0));
RuleFor(x => x.Items)
.NotEmpty()
.ForEach(itemRule => itemRule.ChildRules(items =>
{
items.RuleFor(x => x.Name).NotNull();
}));
}
}
public sealed class MyClass {
public List<int> Ids { get; } = new List<int>();
public List<Item> Items { get; } = new List<Item>();
}
public sealed class Item {
public string Name { get; set; }
}
|
|
When(myClass => myClass.MyCondition, () => {
RuleFor(myClass => customer.Name).NotNull();
}).Otherwise(() => {
RuleFor(customer => customer.Name).MinimumLength(3);
});
|
Overriding the error message
|
this.RuleFor(x => x.Name)
.WithMessage("Error message on {PropertyName}.");
|
Placeholder
|
|
{PropertyName} |
The name of the property being validated
|
{PropertyValue} |
The value of the property being validated, these include the predicate validator (‘Must’ validator), the email and the regex validators.
|
Built-in Validators and their Placeholders
|
// test first if Name is not null, then even if Name is null test if lenght is >= 3
RuleFor(x => x.Name).NotNull().MinimumLength(3);
// test first if Name is not null, then only if Name is not null test if lenght is >= 3
RuleFor(x => x.Name).Cascade(CascadeMode.StopOnFirstFailure).NotNull().MinimumLength(3);
// change the default cascade mode
public MyClassValidator() {
// First set the cascade mode
CascadeMode = CascadeMode.StopOnFirstFailure;
RuleFor(x => x.Name).NotNull().MinimumLength(3);
|
|
var validator = new MyClassValidator();
var result = await validator.ValidateAsync(myClass);
public sealed class MyClassValidator : AbstractValidator<MyClass>
{
SomeExternalWebApiClient client;
public MyClassValidator(SomeExternalWebApiClient client)
{
this.client = client;
this.RuleFor(x => x.Name)
.MustAsync(async (name, cancellation) => {
bool nameExists = await client.NameExists(name);
return !nameExists;
}).WithMessage("Name is not valid.");
}
private static bool IsValid(string value)
{
return value != null;
}
}
|
Throwing Exceptions
|
try
{
validator.ValidateAndThrow(mc);
}
catch (ValidationException e)
{
foreach (var failure in e.Errors)
{
Console.WriteLine(failure.ErrorMessage);
}
}
|
Installer le package NuGet FluentValidation.WebApi
Validator attribute
App_Start\WebApiConfig.cs
|
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// ...
FluentValidationModelValidatorProvider.Configure(config);
|
ItemController.cs
|
[HttpPost]
[Route("")]
[ResponseType(typeof(Item))]
public IHttpActionResult Post(Item item)
{
// if the item is null, the validator is not executed
if (item == null)
{
return this.BadRequest("Item cannot be null.");
}
// if there are validation errors
if (!ModelState.IsValid)
{
return this.BadRequest(ModelState);
}
|
Item.cs
|
// link the class with its validator
[Validator(typeof(ItemValidator))]
public sealed class Item { }
|
App_Start\WebApiConfig.cs
|
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
// register all the validator
AssemblyScanner.FindValidatorsInAssembly(typeof(WebApiConfig).Assembly)
.ForEach(result =>
{
builder.RegisterType(result.ValidatorType).As(result.InterfaceType);
});
// register the ValidatorFactory because its ctor needs an IComponentContext
builder.RegisterType<AutofacValidatorFactory>();
IContainer container = builder.Build();
FluentValidationModelValidatorProvider.Configure(config,
provider => { provider.ValidatorFactory = container.Resolve<AutofacValidatorFactory>(); });
|
AutofacValidatorFactory.cs
|
internal class AutofacValidatorFactory : ValidatorFactoryBase
{
private readonly IComponentContext context;
public AutofacValidatorFactory(IComponentContext context)
{
this.context = context;
}
public override IValidator CreateInstance(Type validatorType)
{
if (this.context.TryResolve(validatorType, out var instance))
{
var validator = instance as IValidator;
return validator;
}
return null;
}
}
|
Ainsi il n'est plus nécessaire de tester ModelState.IsValid dans chaque Controller.
App_Start\WebApiConfig.cs
|
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new ValidateModelStateFilter());
|
ValidateModelStateFilter.cs
|
public class ValidateModelStateFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (!actionContext.ModelState.IsValid)
{
actionContext.Response =
actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, actionContext.ModelState);
|
MyValidatorTest.cs
|
public class MyValidatorTest
{
private readonly MyValidatorTest validator = new MyValidatorTest();
[Fact]
public void ValidationOfProp3_AskProp1AndProp2_Error()
{
var query = new MyQuery
{
Prop1 = "value1",
Prop2 = "value2"
};
this.validator.ShouldHaveValidationErrorFor(x => x.Prop3, query)
.WithSeverity(Severity.Error)
.WithErrorMessage(ValidationMessageResources.MyErrorMessage);
}
|