使用FluentValidation

问题描述

我在项目中使用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);
        };
    }
}