首页 > 解决方案 > 如何使用 C# FluentValidation ValidationContext.RootContextData

问题描述

我是 FluentValidation 的新手,正在尝试创建一个在验证时接受一些上下文/参数的验证器。我创建了一个自定义验证器,在构造函数中我有类似的东西:

RuleFor(request => request.someField).Custom((request, context) => {
    var foo = context.ParentContext.RootContextData["someDependency"];
});

在调用代码中我这样做:

var validator = new FooValidator();
var context = new ValidationContext<SomeRequest>(request);
context.RootContextData["someDependency"] = someDependency;
validator.Validate(context);

什么导致:

System.Collections.Generic.KeyNotFoundException: The given key 'someDependency' was not present in the dictionary.

有任何想法吗?我想传入一些上下文参数的原因是它们来自数据库。如果我将其传递给验证器构造函数,那么在调用 validate 方法时,那些上下文参数可能已经过时了。我也不想在验证器构造函数中从数据库中获取数据,因为我还需要在调用 validate 方法之前/之后获取相同的数据,并且在这种情况下无法进行数据库缓存,所以我会喜欢避免不必要的数据库往返。我已经阅读并且正在做的事情似乎与描述的内容相同https://docs.fluentvalidation.net/en/latest/advanced.html#root-context-data

标签: c#fluentvalidation

解决方案


正如我的 OP 评论中提到的,代码看起来不错,但它可能在 MVC 验证管道阶段失败,并且永远不会进入您的Validate调用。就目前的情况而言,您没有将依赖项添加到字典中,因此它会出错。

可能有几种方法可以解决它。我的第一个想法是引入一个规则集,因此该规则仅在您的Validate调用中执行服务器端。doco 中有一个完整的关于规则集的部分,它很好地涵盖了它。您可能需要将它与一个CustomizeValidator属性结合起来,这样规则集就不会在 MVC 验证管道中执行(我在使用服务器端规则集时从来没有这样做过,但为了完整起见,我已经提到了它)。

这样做的好处是您可能不需要更改很多现有代码。您已经提到您将许多依赖项加载到验证上下文中,因此它可能很合适。

另一种看起来不错但我自己没有尝试过的方法是在BeforeMvcValidation验证拦截器中填充验证上下文。此选项的值将取决于您如何收集这些依赖项以及它们是否用于验证以外的任何其他用途。与基于您的实现描述的规则集相比,它可能需要更多的努力。


推荐阅读