问题描述
我在项目中使用FluentValidation来验证几乎所有进入WebApi的请求。 它工作正常,但已要求我在错误消息中转换属性名称。我的项目必须至少处理法语和英语,因此,例如,我想要实现的是:
- “姓氏”为必填项(英语)
- 'Prénom'est要求(法语案例)
我已经有一个IPropertyLabelService用于其他用途,已注入到要使用的Startup.cs中。它可以在.json中找到属性名称的翻译,该翻译已经可以正常工作了。
我的问题是我不知道如何全局使用它。我知道FluentValidation的文档说要在启动文件中设置ValidatorOptions.displayNameResolver,如下所示:
FluentValidation.ValidatorOptions.displayNameResolver = (type,memberInfo,expression) => {
// Do something
};
我不知道该如何在其中使用IPropertyLabelService,因为Startup.ConfigureServices方法尚未结束,因此我无法解析我的服务...
任何其他实现此行为的解决方案也非常受欢迎。我考虑过使用.WithMessage()或.WithName(),但是我有大量的验证器,要单独将其添加到所有验证器中确实很长。
解决方法
我在FluentValidation问题跟踪器上回答了这个问题,但出于完整性考虑,这里也包含答案:
设置FluentValidation.ValidatorOptions.Global.DisplayNameResolver
是全局处理此问题的正确方法(或者您可以在各个规则级别使用WithName)。
您需要确保全局设置一次。如果需要先初始化服务提供者,则请确保在配置服务提供者之后调用它(但请确保仍只设置一次)。
.NET Core中的“选项”配置机制允许您将配置推迟到构造点服务之后,因此您可以创建一个实现IConfigureOptions的类,该类将在特定阶段的配置阶段实例化并执行。选项类型。 FluentValidation本身不提供任何选项配置,因此您可以插入一个内置的选项类(ASP.NET的MvcOptions可能是最简单的,但是如果您不使用mvc,也可以使用其他选项)
例如,您可以在ConfigureServices方法中执行以下操作:
public void ConfigureServices(IServiceCollection services) {
// ... your normal configuration ...
services.AddMvc().AddFluentValidation();
// Afterwards define some deferred configuration:
services.AddSingleton<IConfigureOptions<MvcOptions>,DeferredConfiguration>();
}
// And here's the configuration class. You can inject any services you need in its constructor as with any other DI-enabled service. Make sure your IPropertyLabelService is registered as a singleton.
public class DeferredConfiguration : IConfigureOptions<MvcOptions> {
private IPropertyLabelService _labelService;
public DeferredConfiguration(IPropertyLabelService labelService) {
_labelService = labelService;
}
public void Configure(MvcOptions options) {
FluentValidation.ValidatorOptions.Global.DisplayNameResolver = (type,memberInfo,expression) => {
return _labelService.GetPropertyOrWhatever(memberInfo.Name);
};
}
}