【问题标题】:ASP.NET Core Model Binding Error Messages LocalizationASP.NET Core 模型绑定错误消息本地化
【发布时间】:2017-04-11 05:55:15
【问题描述】:

我正在使用 ASP.NET Core,并尝试本地化应用程序。我设法使用 new asp .net 核心资源来本地化控制器和视图,并使用 old 资源来本地化错误消息以进行模型验证。 但是,当错误消息未链接到模型字段注释(如“必需”)并且模型绑定的数据不正确(如预期数字的文本)时,我收到如下错误,我是无法本地化:

“值 'abc' 对 ID 无效。”

当我在View 中为ID 属性输入abc 时,由于无法对字段进行模型绑定,并且它在字段附近显示验证消息,说“值'abc'对 ID 无效。”。这是我正在使用的课程:

public class Country : IHasID
{
    public int ID { get; set; }

    [Required(ErrorMessageResourceType = typeof(L.Val),
    ErrorMessageResourceName = "NameR")]
    [MaxLength(100, ErrorMessageResourceType = typeof(L.Val), 
    ErrorMessageResourceName = "Max")]
    public string Name { get; set; }

    /*Some other properties*/
}

我在互联网上发现的类似问题要么是针对旧的 asp .net 版本,要么没有帮助我解决问题。

【问题讨论】:

  • 我想知道为什么您会在 Test 属性上收到验证消息,因为它根本不包含任何验证属性
  • 用户可能会在相应的 HTML 字段中插入文本,这会产生模型错误(我正在尝试更改的消息 od)。

标签: c# .net localization asp.net-core asp.net-core-localization


【解决方案1】:

自定义框架模型绑定错误信息,需要为ModelBindingMessageProvider的不同错误信息访问器设置自定义访问器。

示例

您可以在此处下载本文所述内容的完整源代码。该存储库包含 ASP.NET Core 2.0 (VS 2017.3)ASP.NET Core 1.1 (VS 2015) 的示例:

你也可以在这里看到这个例子,现场直播:

默认错误信息

这些是框架在模型绑定到属性失败时显示的默认错误消息:

MissingBindRequiredValueAccessor    A value for the '{0}' property was not provided.
MissingKeyOrValueAccessor           A value is required.
ValueMustNotBeNullAccessor          The value '{0}' is invalid. 
AttemptedValueIsInvalidAccessor     The value '{0}' is not valid for {1}.
UnknownValueIsInvalidAccessor       The supplied value is invalid for {0}.
ValueIsInvalidAccessor              The value '{0}' is invalid.
ValueMustBeANumberAccessor          The field {0} must be a number.

除了上述消息之外,ASP.NET Core 2.0 也有这些消息:

MissingRequestBodyRequiredValueAccessor       A non-empty request body is required.
NonPropertyAttemptedValueIsInvalidAccessor    The value '{0}' is not valid.
NonPropertyUnknownValueIsInvalidAccessor      The supplied value is invalid.
NonPropertyValueMustBeANumberAccessor         The field must be a number.

本地化 ASP.NET Core 模型绑定错误消息

要本地化 ASP.NET Core 模型绑定错误消息,请执行以下步骤:

  1. 创建资源文件 - 在您的解决方案中的 Resources 文件夹下创建一个资源文件,并将文件命名为 ModelBindingMessages.fa.resx .该名称可以是其他任何名称,但我们将使用它来创建本地化程序。在示例中,我使用了 fa(波斯)文化。

  2. 添加资源键 - 打开资源文件并添加要用于本地化错误消息的键和值。我使用了如下图所示的键和值:

    我使用的键和原始消息一样,除了ValueMustNotBeNull的键与ValueIsInvalid相同,所以我使用了Null value is invalid.

  3. 配置选项 - 在ConfigureServices 方法中,添加Mvc 时,配置其选项以设置ModelBindingMessageProvider 的消息访问器:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLocalization(options => { options.ResourcesPath = "Resources"; });
        services.AddMvc(options =>
        {
            var F = services.BuildServiceProvider().GetService<IStringLocalizerFactory>();
            var L = F.Create("ModelBindingMessages", "AspNetCoreLocalizationSample");
            options.ModelBindingMessageProvider.ValueIsInvalidAccessor =
                (x) => L["The value '{0}' is invalid.", x];
            options.ModelBindingMessageProvider.ValueMustBeANumberAccessor =
                (x) => L["The field {0} must be a number.", x];
            options.ModelBindingMessageProvider.MissingBindRequiredValueAccessor =
                (x) => L["A value for the '{0}' property was not provided.", x];
            options.ModelBindingMessageProvider.AttemptedValueIsInvalidAccessor =
                (x, y) => L["The value '{0}' is not valid for {1}.", x, y];
            options.ModelBindingMessageProvider.MissingKeyOrValueAccessor =
                () => L["A value is required."];
            options.ModelBindingMessageProvider.UnknownValueIsInvalidAccessor =
                (x) => L["The supplied value is invalid for {0}.", x];
            options.ModelBindingMessageProvider.ValueMustNotBeNullAccessor =
                (x) => L["Null value is invalid.", x];
        })
        .AddDataAnnotationsLocalization()
        .AddViewLocalization();
        services.Configure<RequestLocalizationOptions>(options =>
        {
            var supportedCultures = new[]{new CultureInfo("en"), new CultureInfo("fa")};
            options.DefaultRequestCulture = new RequestCulture("en", "en");
            options.SupportedCultures = supportedCultures;
            options.SupportedUICultures = supportedCultures;
        });
    }
    

    还要在Configure方法的开头添加这段代码:

    var supportedCultures = new[] { new CultureInfo("en"), new CultureInfo("fa") };
    app.UseRequestLocalization(new RequestLocalizationOptions()
    {
        DefaultRequestCulture = new RequestCulture(new CultureInfo("en")),
        SupportedCultures = supportedCultures,
        SupportedUICultures = supportedCultures
    });
    

ASP.NET Core 2.0 重要说明

在 ASP.NET Core 2.0 中,模型绑定消息提供程序属性已获得 只读,但已为每个属性添加了一个 setter 方法。

例如,设置 ValueIsInvalidAccessor,你应该使用SetValueIsInvalidAccessor() 这种方法:

options.ModelBindingMessageProvider.SetValueIsInvalidAccessor (
    (x) => L["The value '{0}' is invalid.", x]);

【讨论】:

  • 这看起来很酷,但是我无法让它在 Core 1.1 中应用 - 资源文件在那里,并且项目其余部分的本地化工作正常,但使用上述我仍然收到默认错误消息...即ValueMustNotBeNullAccessor 上的“{0} 字段是必需的” - 所以它甚至不采用英文值...有什么想法吗?
  • @RemarkLima github 存储库已添加。 github.com/r-aghaei/AspNetCoreLocalizationSample
  • @Marko github 存储库已添加。 github.com/r-aghaei/AspNetCoreLocalizationSample
  • 很抱歉,但在 Core 2.0 中,此方法不适用于 [Required] 注释生成的验证消息。好像错误字符串The XYZ field is required.不能这样翻译。
  • 是的,@RezaAghaei,你是对的。我建议您在此处添加您的答案,某些注释无法使用ModelBindingMessageProvider 方法进行翻译,但需要在将触发翻译的注释中添加一个静态 ErrorMessage 字符串。 [Required] 案例就是其中之一,它可能是将大多数人带到这里的案例。我花了几个小时才明白这一点。
【解决方案2】:

参考这篇详细描述the side effects for using BuildServiceProvider inside ConfigureServices 的帖子和关于resolving services inside ConfigureServices 的答案,最后但并非最不重要的一点是,考虑到refered improved answer by Andrew Lock,本地化模型绑定错误消息的正确方法应该是创建一个实现IConfigureOptions&lt;T&gt;的自定义配置类,然后在启动时注册如下:

public class ConfigureModelBindingLocalization : IConfigureOptions<MvcOptions>
{
    private readonly IServiceScopeFactory _serviceFactory;
    public ConfigureModelBindingLocalization(IServiceScopeFactory serviceFactory)
    {
        _serviceFactory = serviceFactory;
    }

    public void Configure(MvcOptions options)
    {
        using(var scope = _serviceFactory.CreateScope())
        {
            var provider = scope.ServiceProvider;
            var localizer = provider.GetRequiredService<IStringLocalizer>();

            options.ModelBindingMessageProvider.SetAttemptedValueIsInvalidAccessor((x, y) => 
                localizer["The value '{0}' is not valid for {1}.", x, y]);

            options.ModelBindingMessageProvider.SetMissingBindRequiredValueAccessor((x) => 
                localizer["A value for the '{0}' parameter or property was not provided.", x]);

            options.ModelBindingMessageProvider.SetMissingKeyOrValueAccessor(() => 
                localizer["A value is required."]);

           options.ModelBindingMessageProvider.SetMissingRequestBodyRequiredValueAccessor(() =>
               localizer["A non-empty request body is required."]);

           options.ModelBindingMessageProvider.SetNonPropertyAttemptedValueIsInvalidAccessor((x) =>
               localizer["The value '{0}' is not valid.", x]);

           options.ModelBindingMessageProvider.SetNonPropertyUnknownValueIsInvalidAccessor(() =>
               localizer["The supplied value is invalid."]);

           options.ModelBindingMessageProvider.SetNonPropertyValueMustBeANumberAccessor(() =>
               localizer["The field must be a number."]);

           options.ModelBindingMessageProvider.SetUnknownValueIsInvalidAccessor((x) =>
               localizer["The supplied value is invalid for {0}.", x]);

           options.ModelBindingMessageProvider.SetValueIsInvalidAccessor((x) =>
               localizer["The value '{0}' is invalid.", x]);

           options.ModelBindingMessageProvider.SetValueMustBeANumberAccessor((x) =>
               localizer["The field {0} must be a number.", x]);

           options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor((x) =>
               localizer["The value '{0}' is invalid.", x]);
        }
    }
}

最后在启动时注册新的配置类:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureModelBindingLocalization>();

    // ...
}

【讨论】:

  • 这是 asp.net core 5 的有效答案
  • 想补充一点,如果您使用 Orchestra PO 本地化,您可以声明一个空类并调用 IStringLocalizer 并注入它并使用它来代替 localizer 变量
  • 我收到此错误No service for type 'Microsoft.Extensions.Localization.IStringLocalizer' has been registered. .... 使用 asp.net core 6 并将 builder.Services.AddLocalization(options =&gt; options.ResourcesPath = "Resources"); 添加到 program.cs ... 还添加了 .AddViewLocalization()
【解决方案3】:

在 .NET Core 3.1 和 .NET 5 中测试。 创建一个确定 UICulture 的私有方法

private string GetStringValidationError()
    {
        CultureInfo uiCultureInfo = Thread.CurrentThread.CurrentUICulture;

        string errorMessaeg = string.Empty;

        errorMessaeg = uiCultureInfo.ToString() == "ar" ? "هذا الحقل مطلوب" : "This field is required";
        return errorMessaeg;
    }

之后,您可以将此方法附加到 Func 委托,作为 SetValueMustNotBeNullAccessor 方法的第一个参数,如下所示:

options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(value => GetStringValidationError());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-30
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 2018-12-11
    • 1970-01-01
    相关资源
    最近更新 更多