服务器端验证用自定义DisplayAttribute:Name,配合IDisplayMetadataProvider实现表单翻译的问题
自定义DisplayAttribute翻译的IDisplayMetadataProvider实现与常见问题解答
你通过实现IDisplayMetadataProvider来复用DisplayAttribute的Name属性做表单元素翻译的思路很实用,下面针对这类实现的常见疑问和优化点逐一说明:
1. 怎么让这个元数据提供器生效?
要让你的DisplayAttributeMetadataProvider真正起作用,得在项目的服务配置里注册它。比如在.NET 6+的Program.cs中:
services.AddControllersWithViews() .AddMvcOptions(options => { options.ModelMetadataDetailsProviders.Add(new DisplayAttributeMetadataProvider()); });
如果是用Razor Pages的项目,就把AddControllersWithViews()换成AddRazorPages()就行。
2. 代码里没处理DisplayAttribute为空的情况怎么办?
你的当前代码如果遇到没有标记DisplayAttribute的属性,display会是null,直接访问display.Name会抛出空引用异常。可以加个空值判断做兼容:
public void CreateDisplayMetadata(DisplayMetadataProviderContext context) { var metadata = context.DisplayMetadata; var display = context.Attributes.OfType<DisplayAttribute>().FirstOrDefault(); if (display == null) { // 没找到DisplayAttribute就用默认逻辑,比如保留属性原名 return; } metadata.DisplayName = () => new MakeItTranslatable(display.Name); }
3. 怎么确保翻译逻辑MakeItTranslatable能正确输出字符串?
DisplayName要求是返回string的委托,如果你MakeItTranslatable是自定义类型,得确保它能被转换成字符串,或者直接在委托里调用翻译方法。比如假设你的类型有个GetTranslation()方法获取最终翻译文本:
metadata.DisplayName = () => new MakeItTranslatable(display.Name).GetTranslation();
4. 能不能同时翻译DisplayAttribute里的其他属性?
当然可以,比如Description(描述文本)、Prompt(输入框提示)这些属性,都可以一起处理:
if (display != null) { metadata.DisplayName = () => new MakeItTranslatable(display.Name).GetTranslation(); if (!string.IsNullOrEmpty(display.Description)) { metadata.Description = () => new MakeItTranslatable(display.Description).GetTranslation(); } if (!string.IsNullOrEmpty(display.Prompt)) { metadata.Prompt = () => new MakeItTranslatable(display.Prompt).GetTranslation(); } }
5. 和项目里的内置本地化逻辑冲突了怎么办?
默认情况下,你添加的自定义提供器会在内置的元数据提供器之后执行,会覆盖之前的设置。如果需要调整优先级,可以用Insert方法指定注册位置,或者在代码里直接强制替换元数据的值,不用考虑之前的设置。
内容的提问来源于stack exchange,提问作者kmasalski
相关产品推荐
相关产品推荐

