FluentValidation 在 AspNetMvc n 层项目中的使用

FluentValidation usage in AspNetMvc n-tier project

我有一个多层项目。图层如下:

我在实体层中有一个类别class:

public class Category : IEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

我在业务层也有一个CategoryValidatorclass:

public class CategoryValidator : AbstractValidator<Category>
{
    public CategoryValidator(IEnumerable<Category> categories)
    {
        RuleFor(x => x.Name).NotEmpty().MaximumLength(50);
    }
}

我在核心层有一个class用于验证。

public class ValidatorTool
{
    public static void FluentValidate(IValidator validator, object entity)
    {
        var result = validator.Validate(entity);
        if (result.Errors.Any())
            throw new ValidationException(result.Errors);
    }
}

我正在使用 FluentValidate 方法在业务层中执行验证。

但是到了MvcWebUI层就卡住了。根据 FluentValidation documentation,我需要将属性应用到实体 class,如下所示:

[Validator(typeof(PersonValidator))]

但是由于业务层引用了实体层,我无法到达实体层中的CategoryValidatorclass。 (圆圈参考)

我该如何解决这个问题? 我是否错误地创建了图层? 或者我应该在 Web 层中再次将实体定义为模型? 请帮助我。

通常你有两种方式来执行验证:

  1. 验证视图模型(在大多数情况下使用)
  2. 内部业务实体验证(最常与 1-st 一起使用)

对于第 1 点,您验证放置在您的 Web 项目中的视图模型(在客户端和服务器上)。在那种情况下,您也应该在 Web 项目中放置 view model validators[Validator(typeof(PersonValidator))] 属性需要链接动作的视图模型参数和动作本身以在动作执行之前执行验证。如文档所示:

Internally, FluentValidation’s MVC integration makes use of a validator factory to know how to work out which validator should be used to validate a particular type. By default, FluentValidation ships with an AttributedValidatorFactory that allows you to link a validator to the type that it validates by decorating the class to validate with an attribute that identifies its corresponding validator.

如果要验证业务模型(第 2 点),not/not 仅查看模型,您需要将 实体验证器 放置到业务项目并注册它们在你的 IoC 容器中(example with Castle Windsor),然后更改验证器工具:

public class ValidatorTool
{
    public static void FluentValidate<T>(IContainer container, T entity) // replace IContainer with your actual container interface name
    {
        var validator = container.Resolve<IValidator<T>>();
        var result = validator.Validate(entity);
        if (result.Errors.Any())
            throw new ValidationException(result.Errors);
    }
}

首先,您可能不应该直接在 UI 中公开您的实体,因此我建议您在那里创建新模型并专门为它们编写验证程序。

假设连接正确,这种方法意味着验证器在 MVC 应用程序中的 HTTP POST 期间自动触发,并且模型状态自动更新为错误列表。

我广泛使用这种方法,尽管是在调用内部 API 的 MVC 应用程序中。

在我的大多数情况下,MVC 客户端验证模型,如果它通过检查,则调用 API 或服务层,之后使用 DTO / 服务 / 实体模型映射到 Automapper .

MVC 验证通常很简单,会检查必填字段、长度等。

API 再次进行验证,但它是在实体上进行的,而且这次更深入,因为它检查重复项、无效的实体状态等。

我想补充的最后一条评论。我不会在验证错误时抛出异常。 UI 应该使用 ModelState 和服务层 returns 客户端知道如何合并回 ModelState 的结果,所以这两种情况都会导致用户得到一个很好的错误列表来处理。

希望对您有所帮助!