王玉平 發表於 2025-3-22 08:57:15

ASP.NET Core 模型验证消息的本地化新姿势详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">疑问产生</a></li><li><a href="#_label1">默认消息</a></li><li><a href="#_label2">查找默认消息</a></li><li><a href="#_label3">本地化默认消息</a></li><li><a href="#_label4">建立语言扩展包</a></li><li><a href="#_label5">最终效果</a></li><li><a href="#_label6">Nuget包</a></li></ul></div><p>最近在研究系统本地化的问题,不可避免要实现模型类的验证消息本地化。毕竟这些错误消息是要返回给用户的。</p>
<p class="maodian"><a name="_label0"></a></p><h2>疑问产生</h2>
<p>在MVC模型下,我们会使用模型类对请求参数进行绑定和验证。举个例子:</p>
<div class="jb51code"><pre class="brush:csharp;">public class UserDto
{
   
    public string Name{get; set;}
   
   
    public int? Age {get; set; }
}</pre></div>
<p>这样本身没有什么问题,但如果有大量模型要做本地化改造,那可就是个大工程了。</p>
<p>我们不禁要问,为什么要指定ErrorMessage,默认的错误消息不能用吗?毕竟我们人工指定的错误消息除了字段名之外,其它都完全一样,实在没有必要逐个指定。</p>
<p class="maodian"><a name="_label1"></a></p><h2>默认消息</h2>
<p>我们来改造一下看看,删除掉指定的ErrorMessage。</p>
<div class="jb51code"><pre class="brush:csharp;">public class UserDto
{
   
    public string Name{get; set;}
   
   
    public int? Age {get; set; }
}</pre></div>
<p>如果没有传入参数导致验证不通过,会得到如下消息:</p>
<blockquote><p>&quot;The Name field is required.&quot;<br />&quot;The Age field is required.&quot;</p></blockquote>
<p>没错,默认消息是英文的,这对我们来说完全不可用&mdash;&mdash;这对用户很不友好,难怪要人工设置ErrorMessage。</p>
<p class="maodian"><a name="_label2"></a></p><h2>查找默认消息</h2>
<p>那有没有可能直接把默认消息本地化呢?如果可以,那就不用再麻烦地设置ErrorMessage了。</p>
<p>通过查看<a href="https://source.dot.net/" rel="noopener nofollow" target="_blank">官方源码</a>我们发现,默认消息来自SR类,以RequiredAttribute举例:</p>
<div class="jb51code"><pre class="brush:csharp;">public RequiredAttribute()
      : base(() =&gt; SR.RequiredAttribute_ValidationError)
{
}</pre></div>
<p>SR类的内容简略如下:</p>
<div class="jb51code"><pre class="brush:csharp;">internal static partial class SR
{
    internal static global::System.Resources.ResourceManager ResourceManager =&gt; s_resourceManager ?? (s_resourceManager = new global::System.Resources.ResourceManager(typeof(FxResources.System.ComponentModel.Annotations.SR)));
    internal static string @RequiredAttribute_ValidationError =&gt; GetResourceString("RequiredAttribute_ValidationError", @"The {0} field is required.");
}</pre></div>
<p>上面的代码中,GetResourceString最终会调用内部声明的ResourceManager。而 ResourceManager会根据传入的类型参数查找本地化资源。</p>
<p class="maodian"><a name="_label3"></a></p><h2>本地化默认消息</h2>
<p>通过上面的分析,如果要使用中文内容,我们只要把本地化的消息放入FxResources.System.ComponentModel.Annotations.SR.zh-CN.resources 即可。动手之前,我们再确认一下。</p>
<p>ILSpy 打开 System.ComponentModel.Annotations.dll,确实可以看到默认的资源FxResources.System.ComponentModel.Annotations.SR.resources,证明我们的分析没错。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202503/202503220857081.png" /></p>
<p>默认(中立语言)资源里面包含了错误消息,也包含了内部的异常消息。我们可以全部或者选择地本地化它们。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202503/202503220857082.png" /></p>
<p class="maodian"><a name="_label4"></a></p><h2>建立语言扩展包</h2>
<p>我们建立一个项目,名为 FxResources.System.ComponentModel.Annotations。根据默认规则,在项目中建立的资源会自动添加命名空间作为前缀。</p>
<p>因此我们只需要再创建名为 SR的资源即可。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202503/202503220857083.png" /></p>
<p>如图,我们建立了对应的中文简体和中文繁体资源,这样就大功告成了!</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202503/202503220857084.png" /></p>
<p>说明:zh-Hans兼容zh-CN、zh-SG;zh-Hant兼容zh-TW、zh-MO、zh-HK。严格讲港澳台繁体略有差异,但在一般场景可以忽略。</p>
<p class="maodian"><a name="_label5"></a></p><h2>最终效果</h2>
<p>同样是之前的例子,我们不需要再指定ErrorMessage。</p>
<div class="jb51code"><pre class="brush:csharp;">public class UserDto
{
   
    public string Name{get; set;}
   
   
    public int? Age {get; set; }
}</pre></div>
<p>现在我们得到的消息是这样,看起来还不错。</p>
<blockquote><p>&quot;Name 字段为必填项。&quot;<br />&quot;Age 字段为必填项。&quot;</p></blockquote>
<p>注意:如果你的项目没有启用国际化功能,你需要设置默认的文化为中文:CultureInfo.DefaultThreadUICulture = CultureInfo.GetCultureInfo(&quot;zh-Hans&quot;)</p>
<p class="maodian"><a name="_label6"></a></p><h2>Nuget包</h2>
<p>为方便大家使用,已经将语言资源打包为语言包,大家直接安装到项目即可。</p>
<blockquote><p>Install-Package FxResources.System.ComponentModel.Annotations.zh-Hans -Version 9.0.0</p></blockquote>
<p>.NET 不同版本的资源之间有略微差异,大家选择对应的版本安装即可。</p>
頁: [1]
查看完整版本: ASP.NET Core 模型验证消息的本地化新姿势详解