【问题标题】:Validate DateTime with FluentValidator使用 FluentValidator 验证日期时间
【发布时间】:2011-10-15 13:07:05
【问题描述】:

这是我的 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 = "");
    }
}

尝试使用无效日期格式创建人员时:

观察

在我的 CreatePersonModel 类中,DateBirth 属性是 DateTime 类型,asp.net MVC 验证已为我完成。

但我想自定义错误消息使用 FluentValidation

我不想更改属性的类型,原因如下:

CreatePersonValidator.cs 类中,验证是检查日期是否过去:

.LessThan (p => DateTime.Now)

问题

如何在不使用 DataAnnotations(使用 FluentValidator)的情况下自定义错误消息。

【问题讨论】:

    标签: asp.net-mvc-3 datetime fluentvalidation


    【解决方案1】:
    public CreatePersonValidator()
    {
        RuleFor(courseOffering => courseOffering.StartDate)
           .Must(BeAValidDate).WithMessage("Start date is required");
    
        //....
    }
    
    private bool BeAValidDate(DateTime date)
    {
        return !date.Equals(default(DateTime));
    }
    

    【讨论】:

    • 在假设 DateTime 可以为空的情况下使用 .NotNull() 来覆盖无效日期吗?
    • 这也会创建客户端验证吗?
    【解决方案2】:

    查看 GitHub 上的 Fluent Validation 文档:

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

    在应用小于验证器之前,尝试添加正则表达式验证器以确保用户的输入(字符串)可以正确解析为日期。

    编辑

    在运行了几个测试用例并查看了 Fluent Validator 的源代码后,我承认上述方法行不通。

    您得到的标准错误是在模型绑定阶段添加的,该阶段发生在流式验证框架可以访问和检查模型之前。

    我认为框架的作者很聪明,将他们的验证代码注入模型绑定阶段。好像不是。

    所以简短的回答是你想做的事情似乎不可能。

    【讨论】:

    • 正如我在问题中所说,“我不想更改属性的类型。” RegEx 将适用于这种情况,无论是string!不在DateTime
    • 用户的输入是一个字符串...... MVC 框架需要将其动态转换为 DateTime 以便将其放入您的模型类中。我不建议更改模型类中的数据类型。首先对用户的输入执行正则表达式检查,以确保转换可以成功,并对那些不能成功的情况做出适当的响应。然后执行小于检查。
    • 好的...我再次查看了 FluentValidation 框架,你是对的,它的方法是根据你尝试验证的模型类型提供扩展方法,所以他们说的是正则表达式不允许,因为它是 DateTime。如果这个框架真的以这种方式工作,我个人不会使用它!您需要能够拦截用户输入并在将其映射到模型类之前对其进行验证。如果有人想指出为什么这个框架的设计没有缺陷,我很想听听。 ;)
    • 没错,我的模型是 DateTime。要使用正则表达式验证它必须转换为字符串。我想到了类似的东西,操纵 DataAnnotations(我相信他负责这个验证,但我可能错了),所以可以在不改变我的模型的情况下自定义错误消息。
    • 顺便说一句,流式验证将自己描述为“一个小型 .NET 验证库,它使用流式接口和 lambda 表达式为您的业务对象构建验证规则。”这里的关键词是“业务对象”。我一直喜欢将我的业务对象放在一个单独的层中,并将模型类视为控制器和视图之间的契约。这是额外的工作,但可以很好地分离关注点。
    【解决方案3】:

    正如 Stewart 所提到的,以这种方式单独使用 FluentValidation 来获取模型绑定是不可能的。不过,我会提出两个想法/建议:

    1. 如果您确实无法将 ViewModel 类型从 DateTime 更改为字符串,您始终可以在模型绑定后自行清除模型状态,然后手动运行验证器(我假设您已经绑定 FluentValidation 以在模型绑定后自动执行)。
    2. 在这样的场景中,我会将属性更改为字符串,然后使用 AutoMapper 将其映射到 DateTime 中,以用于我最终需要它成为的任何业务对象/域模型/服务合同请求。 这样,您可以在模型绑定的两侧获得最大的解析和转换灵活性。

    【讨论】:

      【解决方案4】:

      试试这个

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

      【讨论】:

        【解决方案5】:

        我使用非常简单的代码将其与DateTime? 一起使用。如果您使用内置验证器NotNull(),那么您将获得客户端验证,这有两个好处。

        1. 您不必担心人们在其他答案中谈论的所有模型绑定内容。是客户端! ;)
        2. 用户输入的日期不会被“清除”。无效日期将被 Post 设置为 null,模型绑定为 null,验证错误,现在用日期中的 null 值响应视图。这发生得很快,因此用户看不到日期有什么问题。

        这是我使用的代码:

        RuleFor(x => x.CompleteDate).NotNull().WithMessage("Complete Date is not a valid date.");
        

        我在 2021 年 11 月 31 日(11 月没有第 31 天)对它进行了测试,它在客户端验证方面效果很好。

        赢了!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-13
          相关资源
          最近更新 更多