ASP.NET Core 模型绑定错误消息本地化
Posted
技术标签:
【中文标题】ASP.NET Core 模型绑定错误消息本地化【英文标题】:ASP.NET Core Model Binding Error Messages Localization 【发布时间】: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)。
【参考方案1】:
自定义框架模型绑定错误信息,需要为ModelBindingMessageProvider
的不同错误信息访问器设置自定义访问器。
示例
您可以在此处下载本文所述内容的完整源代码。该存储库包含 ASP.NET Core 2.0 (VS 2017.3) 和 ASP.NET Core 1.1 (VS 2015) 的示例:
r-aghaei/AspNetCoreLocalizationSample你也可以在这里看到这个例子,现场直播:
aspnetcorelocalizationsample.azurewebsites.net默认错误信息
这些是框架在模型绑定到属性失败时显示的默认错误消息:
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 模型绑定错误消息,请执行以下步骤:
创建资源文件 - 在您的解决方案中的 Resources 文件夹下创建一个资源文件,并将文件命名为 ModelBindingMessages.fa.resx .该名称可以是其他任何名称,但我们将使用它来创建本地化程序。在示例中,我使用了 fa(波斯)文化。
添加资源键 - 打开资源文件并添加要用于本地化错误消息的键和值。我使用了如下图所示的键和值:
我使用的键和原始消息一样,除了ValueMustNotBeNull
的键与ValueIsInvalid
相同,所以我使用了Null value is invalid.。
配置选项 - 在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<T>
的自定义配置类,然后在启动时注册如下:
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 => 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());
【讨论】:
以上是关于ASP.NET Core 模型绑定错误消息本地化的主要内容,如果未能解决你的问题,请参考以下文章