首页 > 解决方案 > 如何避免 FluentValidation 中的重复外部调用

问题描述

我正在为一个需要许多类似/相同的数据库调用的类(例如 Car)编写验证。

RuleFor(c => c.Id).MustAsync(async (car, id, context, cancellation) => 
{
    return await _carRepository.Get(id) != null;
}).WithMessage("Car with id '{PropertyValue}' does not exist!");

RuleFor(c => c.Model).MustAsync(async (car, model, context, cancellation) => 
{
    var expectedModel = (ModelType)context.ParentContext.RootContextdata["ExpectedModel"]
    var databaseCar = await _carRepository.Get(car.Id); // Repeated database call
    return databaseCar.Model == expectedModel;
}).WithMessage('Stored car does not have the expected model.');

理想情况下,我会执行一次此调用,但不建议将结果存储为验证器实例上的成员,并且ValidateAsync使用添加到上下文中的数据库结果覆盖(类似于ExpectedModel上面的示例)会导致检索它的代码相当笨拙.

我错过了什么吗?

标签: c#validationfluentvalidation

解决方案


一种快速的解决方案可能是在您的 Repository 类上添加某种记忆/缓存,以便在同一上下文中对同一 Car 的多个请求(例如 HTTP 请求)将记住并返回同一对象,而无需多次往返。但可能有更好的方法。

有不同级别的验证需要考虑。正如 Jammer 所指出的,FluentValidation 通常用于验证给定模型的一致性:客户端是否向我发送了表面上看起来是有效请求的东西?在给定当前数据状态的情况下确定该请求是否有效是人们经常以不同方式进行的另一个级别的验证。

您可以两全其美的一种方法是创建一个新类来表示给定的汽车模型以及应用程序验证它所需的一切。

public class ValidCar
{
    public CarModel Model {get; set;}
    public CarEntity Entity {get; set;}
}

首先,您将所需的所有数据组装到一个new ValidCar中,然后您可以在这个新模型上使用 FluentValidation 规则来确保它实际上是有效的。

这种方法的一个好处是您可以让您的业务逻辑方法需要 aValidCar作为参数,而不仅仅是 a CarModel。这使得意外忘记在某些代码路径中验证汽车变得非常困难,并且它预先打包了可能对您计划使用的大部分业务级逻辑有用的数据。


推荐阅读