Подтвердить дату с помощью FluentValidator

Это мой класс ViewModel:

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 = "");
    }
}

При попытке создать человека с недопустимым форматом даты:

Error trying to save the person

Наблюдения

Как и в моем классе CreatePersonModel, свойство DateBirth является типом DateTime, для меня выполнена проверка asp.net MVC.

Но я хочу настроить сообщение об ошибке с помощью FluentValidation.

Я не хочу изменять тип свойства по различным причинам, например:

В классе CreatePersonValidator.cs проверка должна проверить, была ли дата в прошлом:

.LessThan (p => DateTime.Now)

Вопрос

Как настроить сообщение об ошибке без использования DataAnnotations (используя FluentValidator).

Ответ 1

public CreatePersonValidator()
{
    RuleFor(courseOffering => courseOffering.StartDate)
       .Must(BeAValidDate).WithMessage("Start date is required");

    //....
}

private bool BeAValidDate(DateTime date)
{
    return !date.Equals(default(DateTime));
}

Ответ 2

Посмотрите документацию Fluent Validation на GitHub:

https://github.com/JeremySkinner/FluentValidation/wiki

Попробуйте добавить RegEx Validator, чтобы убедиться, что пользовательский ввод (строка) может быть проанализирован как дата правильно, до применения Менеджера проверки менее.

ИЗМЕНИТЬ

Запустив несколько тестовых примеров и посмотрев исходный код для Fluent Validator, я признаю, что вышеупомянутый подход не будет работать.

Стандартная ошибка, которую вы получаете, добавляется во время фазы привязки модели, которая происходит до того, как свободная структура проверки может получить доступ и проверить модель.

Я предположил, что авторы фреймворков были умны и вводили свой код проверки в фазу привязки модели. Похоже, что это не так.

Итак, короткий ответ - это то, что вы хотите сделать, не представляется возможным.

Ответ 3

Как упоминал Стюарт, невозможно использовать FluentValidation в одиночку, чтобы таким образом получить привязку к модели. Я бы предложил две идеи/предложения:

  • Если вы действительно не можете изменить тип ViewModel с DateTime на строку, , вы всегда можете очистить состояние модели после привязки к модели, а затем запустить проверку подлинности вручную (я предполагаю, что вы проводной FluentValidation для автоматического выполнения после привязки модели).
  • В таких сценариях я бы изменил свойство на строку, но затем используйте AutoMapper, чтобы сопоставить это в DateTime для чего-либо бизнес-объект/модель домена/запрос на обслуживание службы. Мне это нужно в конечном итоге. Таким образом, вы получаете максимальную гибкость при анализе и преобразовании с обеих сторон привязки модели.

Ответ 4

Попробуйте этот

RuleFor(f =>
        f.StartDate).Cascade(CascadeMode.StopOnFirstFailure).NotEmpty()
                    .Must(date => date != default(DateTime))
                    .WithMessage("Start date is required");