Reputation: 11059
This is my ViewModel class:
public class CreatePersonModel
{
public string Name { get; set; }
public DateTime DateBirth { get; set; }
public string Email { get; set; }
}
CreatePerson.cshtml
@model ViewModels.CreatePersonModel
@{
ViewBag.Title = "Create Person";
}
<h2>@ViewBag.Title</h2>
@using (Html.BeginForm())
{
<fieldset>
<legend>RegisterModel</legend>
@Html.EditorForModel()
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
CreatePersonValidator.cs
public class CreatePersonValidator : AbstractValidator<CreatePersonModel>
{
public CreatePersonValidator()
{
RuleFor(p => p.Name)
.NotEmpty().WithMessage("campo obrigatório")
.Length(5, 30).WithMessage("mínimo de {0} e máximo de {1} caractéres", 5, 30)
.Must((p, n) => n.Any(c => c == ' ')).WithMessage("deve conter nome e sobrenome");
RuleFor(p => p.DateBirth)
.NotEmpty().WithMessage("campo obrigatório")
.LessThan(p => DateTime.Now).WithMessage("a data deve estar no passado");
RuleFor(p => p.Email)
.NotEmpty().WithMessage("campo obrigatório")
.EmailAddress().WithMessage("email inválido")
.OnAnyFailure(p => p.Email = "");
}
}
When trying to create a person with an invalid date format:
As in my CreatePersonModel class the DateBirth
property is a DateTime
type, the asp.net MVC validation has done for me.
But I want to customize the error message using the FluentValidation.
I do not want to change the type of property for various reasons such as:
In a CreatePersonValidator.cs
class, validation is to check if the date is in the past:
.LessThan (p => DateTime.Now)
How to customize the error message without using DataAnnotations (using FluentValidator).
Upvotes: 32
Views: 64667
Reputation: 25069
I got this to work with DateTime?
using really simple code. If you use the built-in validator NotNull()
, then you get client side validation, which has 2 benefits.
This is the code I used:
RuleFor(x => x.CompleteDate).NotNull().WithMessage("Complete Date is not a valid date.");
I tested it with a date of 11/31/2021 (There is no day 31 in November) and it worked great with client-side validation.
Win!
Upvotes: 1
Reputation: 315
Try this one
RuleFor(f =>
f.StartDate).Cascade(CascadeMode.StopOnFirstFailure).NotEmpty()
.Must(date => date != default(DateTime))
.WithMessage("Start date is required");
Upvotes: 5
Reputation: 926
Have a look at the Fluent Validation documentation on GitHub:
https://github.com/JeremySkinner/FluentValidation/wiki
Try adding a RegEx Validator to ensure that the user's input (a string) can be parsed as a date correctly, prior to applying the Less Than Validator.
EDIT
Having run few test cases and looked at the source code for Fluent Validator I concede that the above approach won't work.
The standard error you get is added during the Model Binding phase, which happens before the fluent validation framework can access and check the model.
I assumed that the framework's authors had been clever and were injecting their validation code into the model binding phase. Looks like they aren't.
So the short answer is what you want to do does not appear to be possible.
Upvotes: 5
Reputation: 570
public CreatePersonValidator()
{
RuleFor(courseOffering => courseOffering.StartDate)
.Must(BeAValidDate).WithMessage("Start date is required");
//....
}
private bool BeAValidDate(DateTime date)
{
return !date.Equals(default(DateTime));
}
Upvotes: 36
Reputation: 4411
As Stewart mentioned, it's not possible to use FluentValidation alone to get in front of the model binding in this way. I'd offer up two ideas/suggestions though:
Upvotes: 1