本地化ASP.NET core模型绑定错误消息
默认错误消息:
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.
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 模型绑定错误消息,请按照下列步骤操作:
创建资源文件 - 在解决方案的Resources文件夹下创建资源文件,并将文件命名为ModelBindingMessages.resx。名称可以是其他任何名称,但我们将使用它来创建本地化程序。
添加资源键 - 打开资源文件并添加要用于本地化错误消息的键和值。我使用了键和值
配置选项 - 在
ConfigureServices方法中,添加时Mvc,配置其选项以设置以下内容的消息访问者ModelBindingMessageProviderservices.AddMvc(options =>
{
IStringLocalizerFactory F = services.BuildServiceProvider().
GetService<IStringLocalizerFactory>();
IStringLocalizer L = F.Create("ModelBindingMessages",
"AspNetCoreLocalizationSample");
options.ModelBindingMessageProvider.
SetValueIsInvalidAccessor((x) => L["The value '{0}' is invalid."]);
options.ModelBindingMessageProvider.SetValueMustBeANumberAccessor(
(x) =>L["The field {0} must be a number."]);
options.ModelBindingMessageProvider.SetMissingBindRequiredValueAccessor(
(x) => L["A value for the '{0}' property was not provided.", x]);
options.ModelBindingMessageProvider.SetAttemptedValueIsInvalidAccessor(
(x, y) => L["The value '{0}' is not valid for {1}.", x, y]);
options.ModelBindingMessageProvider.SetMissingKeyOrValueAccessor(
() => L["A value is required."]);
options.ModelBindingMessageProvider.SetUnknownValueIsInvalidAccessor(
(x) => L["The supplied value is invalid for {0}.", x]);
options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
(x) => L["Null value is invalid.", x]);
}).AddDataAnnotationsLocalization()
.AddViewLocalization();
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]{new CultureInfo("en"), new CultureInfo("zh-cn")};
options.DefaultRequestCulture = new RequestCulture("en", "en");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});还要在
Configure方法开头添加此代码:var supportedCultures = new[] { new CultureInfo("en"), new CultureInfo("zh-CN") };
app.UseRequestLocalization(new RequestLocalizationOptions()
{
DefaultRequestCulture = new RequestCulture(new CultureInfo("en")),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});- 关于属性DisplayAttribute
通过查看源码 在 Microsoft.AspNetCore.Mvc.DataAnnotations.Internal.DataAnnotationsMetadataProvider中有IDisplayMetadataProvider的实现
主要是判断DisplayName不为空和ResourceType为空的时候使用IStringLocalizerFactory
代码片段如下:var dataTypeAttribute = attributes.OfType<DataTypeAttribute>().
if (displayFormatAttribute == null && dataTypeAttribute != null)
{
displayFormatAttribute = dataTypeAttribute.DisplayFormat;
}
var displayMetadata = context.DisplayMetadata; // ConvertEmptyStringToNull
if (displayFormatAttribute != null)
{
displayMetadata.ConvertEmptyStringToNull = displayFormatAttribute.
ConvertEmptyStringToNull;
}
// DataTypeName
if (dataTypeAttribute == null)
{
if (displayFormatAttribute != null && !displayFormatAttribute.HtmlEncode)
{
displayMetadata.DataTypeName = DataType.Html.ToString();
}
}
else
{
displayMetadata.DataTypeName = dataTypeAttribute.GetDataTypeName();
} var containerType = context.Key.ContainerType ?? context.Key.ModelType;
IStringLocalizer localizer = null;
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
localizer = _localizationOptions.DataAnnotationLocalizerProvider(containerType, _stringLocalizerFactory);
} // Description
if (displayAttribute != null)
{
if (localizer != null &&
!string.IsNullOrEmpty(displayAttribute.Description) &&
displayAttribute.ResourceType == null)
{
displayMetadata.Description = () => localizer[displayAttribute.Description];
}
else
{
displayMetadata.Description = () => displayAttribute.GetDescription();
}
} // DisplayFormatString
if (displayFormatAttribute != null)
{
displayMetadata.DisplayFormatString = displayFormatAttribute.DataFormatString;
} // DisplayName
// DisplayAttribute has precedence over DisplayNameAttribute.
if (displayAttribute?.GetName() == null)
{
if (displayNameAttribute != null)
{
if (localizer != null &&
!string.IsNullOrEmpty(displayNameAttribute.DisplayName))
{
displayMetadata.DisplayName = () => localizer[displayNameAttribute.DisplayName];
}
else
{
displayMetadata.DisplayName = () => displayNameAttribute.DisplayName;
}
}
}
else
{
if (localizer != null &&
!string.IsNullOrEmpty(displayAttribute.Name) &&
displayAttribute.ResourceType == null)
{
displayMetadata.DisplayName = () => localizer[displayAttribute.Name];
}
else
{
displayMetadata.DisplayName = () => displayAttribute.GetName();
}
} // EditFormatString
if (displayFormatAttribute != null && displayFormatAttribute.ApplyFormatInEditMode)
{
displayMetadata.EditFormatString = displayFormatAttribute.DataFormatString;
} // IsEnum et cetera
var underlyingType = Nullable.GetUnderlyingType(context.Key.ModelType) ?? context.Key.ModelType;
var underlyingTypeInfo = underlyingType.GetTypeInfo(); if (underlyingTypeInfo.IsEnum)
{
// IsEnum
displayMetadata.IsEnum = true; // IsFlagsEnum
displayMetadata.IsFlagsEnum = underlyingTypeInfo.IsDefined(typeof(FlagsAttribute), inherit: false); // EnumDisplayNamesAndValues and EnumNamesAndValues
//
// Order EnumDisplayNamesAndValues by DisplayAttribute.Order, then by the order of Enum.GetNames().
// That method orders by absolute value, then its behavior is undefined (but hopefully stable).
// Add to EnumNamesAndValues in same order but Dictionary does not guarantee order will be preserved. var groupedDisplayNamesAndValues = new List<KeyValuePair<EnumGroupAndName, string>>();
var namesAndValues = new Dictionary<string, string>(); IStringLocalizer enumLocalizer = null;
if (_localizationOptions.AllowDataAnnotationsLocalizationForEnumDisplayAttributes)
{
if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
enumLocalizer = _localizationOptions.DataAnnotationLocalizerProvider(underlyingType, _stringLocalizerFactory);
}
}
else
{
enumLocalizer = _stringLocalizerFactory?.Create(underlyingType);
} var enumFields = Enum.GetNames(underlyingType)
.Select(name => underlyingType.GetField(name))
.OrderBy(field => field.GetCustomAttribute<DisplayAttribute>(inherit: false)?.GetOrder() ?? ); foreach (var field in enumFields)
{
var groupName = GetDisplayGroup(field);
var value = ((Enum)field.GetValue(obj: null)).ToString("d"); groupedDisplayNamesAndValues.Add(new KeyValuePair<EnumGroupAndName, string>(
new EnumGroupAndName(
groupName,
() => GetDisplayName(field, enumLocalizer)),
value));
namesAndValues.Add(field.Name, value);
} displayMetadata.EnumGroupedDisplayNamesAndValues = groupedDisplayNamesAndValues;
displayMetadata.EnumNamesAndValues = namesAndValues;
} // HasNonDefaultEditFormat
if (!string.IsNullOrEmpty(displayFormatAttribute?.DataFormatString) &&
displayFormatAttribute?.ApplyFormatInEditMode == true)
{
// Have a non-empty EditFormatString based on [DisplayFormat] from our cache.
if (dataTypeAttribute == null)
{
// Attributes include no [DataType]; [DisplayFormat] was applied directly.
displayMetadata.HasNonDefaultEditFormat = true;
}
else if (dataTypeAttribute.DisplayFormat != displayFormatAttribute)
{
// Attributes include separate [DataType] and [DisplayFormat]; [DisplayFormat] provided override.
displayMetadata.HasNonDefaultEditFormat = true;
}
else if (dataTypeAttribute.GetType() != typeof(DataTypeAttribute))
{
// Attributes include [DisplayFormat] copied from [DataType] and [DataType] was of a subclass.
// Assume the [DataType] constructor used the protected DisplayFormat setter to override its
// default. That is derived [DataType] provided override.
displayMetadata.HasNonDefaultEditFormat = true;
}
} // HideSurroundingHtml
if (hiddenInputAttribute != null)
{
displayMetadata.HideSurroundingHtml = !hiddenInputAttribute.DisplayValue;
} // HtmlEncode
if (displayFormatAttribute != null)
{
displayMetadata.HtmlEncode = displayFormatAttribute.HtmlEncode;
} // NullDisplayText
if (displayFormatAttribute != null)
{
displayMetadata.NullDisplayText = displayFormatAttribute.NullDisplayText;
} // Order
if (displayAttribute?.GetOrder() != null)
{
displayMetadata.Order = displayAttribute.GetOrder().Value;
} // Placeholder
if (displayAttribute != null)
{
if (localizer != null &&
!string.IsNullOrEmpty(displayAttribute.Prompt) &&
displayAttribute.ResourceType == null)
{
displayMetadata.Placeholder = () => localizer[displayAttribute.Prompt];
}
else
{
displayMetadata.Placeholder = () => displayAttribute.GetPrompt();
}
}
本地化ASP.NET core模型绑定错误消息的更多相关文章
- 理解ASP.NET Core - 模型绑定&验证(Model Binding and Validation)
注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 模型绑定 什么是模型绑定?简单说就是将HTTP请求参数绑定到程序方法入参上,该变量可以是简单类 ...
- ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”
DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求的详细信息以辅助开发人员更好地进行纠错诊断工作,而ExceptionHandlerMi ...
- ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”
在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...
- ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式
由于ASP.NET Core应用是一个同时处理多个请求的服务器应用,所以在处理某个请求过程中抛出的异常并不会导致整个应用的终止.出于安全方面的考量,为了避免敏感信息的外泄,客户端在默认的情况下并不会得 ...
- ASP.NET MVC模型绑定的6个建议(转载)
ASP.NET MVC模型绑定的6个建议 发表于2011-08-03 10:25| 来源博客园| 31 条评论| 作者冠军 validationasp.netmvc.netasp 摘要:ASP.NET ...
- ASP.NET没有魔法——ASP.NET MVC 模型绑定
在My Blog中已经有了文章管理功能,可以发布和修改文章,但是对于文章内容来说,这里缺少最重要的排版功能,如果没有排版的博客很大程度上是无法阅读的,由于文章是通过浏览器查看的,所以文章的排版其实与网 ...
- ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)
上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...
- [转] ASP.NET MVC 模型绑定的功能和问题
摘要:本文将与你深入探究 ASP.NET MVC 模型绑定子系统的核心部分,展示模型绑定框架的每一层并提供扩展模型绑定逻辑以满足应用程序需求的各种方法. 同时,你还会看到一些经常被忽视的模型绑定技术, ...
- ASP.NET Core 异常和错误处理 - ASP.NET Core 基础教程 - 简单教程,简单编程
原文:ASP.NET Core 异常和错误处理 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 异常和错误处理 上一章节中,我们学习了 ASP.NET Cor ...
随机推荐
- .netcore 在linux 上运行 Helllo World 例子
要想在linux上运行netcore ,需要在linux 安装netcore SKD 下面分两步完成, 首先我的操作系统是 Ubuntu 14.04 ,不同版本可以参考 官网给出的连接 https:/ ...
- 关于无法解析的外部符号 _main
今天在写一段代码的时候,遇到了这个问题,一般遇到这种问题,都是找不到主函数,就是main函数,可是我写的代码是有入口地址main函数的呀.最后发现是自己源文件里,main函数是.c文件,.h文件对应的 ...
- 【SymmetricDS】SymmetricDS是如何工作的
2018-04-20 by 安静的下雪天 http://www.cnblogs.com/quiet-snowy-day/p/8890785.html 本文翻译自SymmetricDS官方文档 ...
- CALayer的基本使用
CALayer需要导入这个框架:#import <QuartzCore/QuartzCore.h> 一.CALayer常用属性 属性 说明 是否支持隐式动画 anchorPoint 和中心 ...
- Spring4新的javaConfig注解
1.@RestController spring4为了更方便的支持restfull应用的开发,新增了RestController的注解,比Controller注解多的功能就是给底下的RequestMa ...
- ann
转自 http://blog.csdn.net/yiluoyan/article/details/45308785 这篇文章接着之前的车牌识别,从输入的车图片中分割识别出车牌之后,将进行下一步:车牌号 ...
- CF570E Pig and Palindromes
完全不会这种类型的$dp$啊…… 考虑回文串一定是可以拆分成(偶数个字母 + 偶数个字母)或者(偶数个字母 + 一个字母 +偶数个字母),两边的偶数个字母其实是完全对称的.因为这道题回文串的长度是给定 ...
- Luogu 3302 [SDOI2013]森林
BZOJ 3123 丑陋的常数,BZOJ 19968ms 卡过. 感觉几个思想都挺经典但是挺套路的. 先考虑不连边的情况怎么做,区间第$k$小,想到主席树,每一个结点维护它到根的前缀和,这样子每一次查 ...
- 5.内网渗透之PTH&PTT&PTK
---------------------------------------------- 本文参考自三好学生-域渗透系列文章 内网渗透之PTH&PTT&PTK PTH(pass-t ...
- WordCount 编码与测试
word count github 项目地址:https://github.com/liuqiang666/wordCount PSP表格 PSP2.1 PSP阶段 预估耗时(小时) 实际耗时( ...