使用 FluentValidation 翻译错误消息中的 属性 名称

Translate property name in error messages with FluentValidation

我在我的项目中使用 FluentValidation 来验证几乎所有进入我的 WebApi 的请求。 它工作正常,但我被要求翻译错误消息中的 属性 名称。我的项目必须至少处理法语和英语,所以例如,我想要实现的是:

我已经有一个用于其他目的的 IPropertyLabelService,它被注入到我想使用的 Startup.cs 中。它在 .json 中找到 属性 名称的翻译,这已经可以正常工作了。

我的问题是我不知道如何在全球范围内使用它。我知道 FluentValidation 的文档说要在启动文件中设置 ValidatorOptions.DisplayNameResolver,像这样:

FluentValidation.ValidatorOptions.DisplayNameResolver = (type, memberInfo, expression) => {
    // Do something
};

我不知道如何在其中使用我的 IPropertyLabelService,因为 Startup.ConfigureServices 方法尚未结束,所以我无法解析我的服务...

实现此行为的任何其他解决方案也非常受欢迎。我考虑过使用 .WithMessage() 或 .WithName() 但我有大量的验证器,将其单独添加到所有验证器真的很长。

我在 FluentValidation 问题跟踪器上回答了这个问题,但为了完整起见,这里也包括答案:

Ssetting FluentValidation.ValidatorOptions.Global.DisplayNameResolver 是全局处理此问题的正确方法(或者您可以在单个规则级别使用 WithName)。

您需要确保这是一次全局设置。如果您需要先初始化服务提供者,请确保在配置服务提供者之后调用它(但确保您仍然只设置一次)。

.NET Core 中的“选项”配置机制允许您将配置推迟到构建点服务之后,因此您可以创建一个 class 实现 IConfigureOptions,它将在特定选项类型的配置阶段。 FluentValidation 本身不提供任何选项配置,因此您可以只挂钩 built-in 选项之一 classes(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);
        };
    }
}