如何在ASP.NET MVC中实现可正常生效的本地化Compare验证属性?
如何在ASP.NET MVC中实现可正常生效的本地化Compare验证属性?
兄弟,我看了你的代码,发现LocalizedCompareAttribute没生效主要是几个细节没处理好,咱们一步步来解决:
首先说你的现有代码里的问题:
- 错误消息的键写错了:你在返回错误时用了
"_errorMessageKey"字符串字面量,而不是你定义的_errorMessageKey变量,根本拿不到正确的本地化消息 HttpContextAccessor没初始化也没正确获取服务:你类里没定义这个字段,还直接new了一个,正确做法应该从验证上下文里拿服务- 没必要自己写比较逻辑:原生的
CompareAttribute已经封装了成熟的比较逻辑,直接继承它复用就行,省得自己踩坑 - 缺少客户端验证支持:如果要前端也能触发验证,得实现
IClientValidatable接口
下面给你两种解决方案,推荐第二种,更简洁可靠:
方案一:修复你现有的LocalizedCompareAttribute
修正后的代码如下,解决了上面的所有问题:
public class LocalizedCompareAttribute : ValidationAttribute, IClientValidatable { private readonly string _otherProperty; private readonly string _errorMessageKey; public LocalizedCompareAttribute(string otherProperty, string errorMessageKey) { _otherProperty = otherProperty; _errorMessageKey = errorMessageKey; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { // 获取要比较的属性信息 var otherPropertyInfo = validationContext.ObjectType.GetProperty(_otherProperty); if (otherPropertyInfo == null) { return new ValidationResult($"Unknown property: {_otherProperty}"); } var otherValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance); // 对比两个属性值 if (!object.Equals(value, otherValue)) { // 从验证上下文获取本地化服务 var localizer = validationContext.GetService<IStringLocalizer<Language>>(); var errorMessage = localizer?[_errorMessageKey] ?? "Passwords do not match."; return new ValidationResult(errorMessage); } return ValidationResult.Success; } // 实现客户端验证规则,让前端也能触发验证 public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "compare" // 对应原生的compare验证类型 }; rule.ValidationParameters.Add("other", $"*.{_otherProperty}"); yield return rule; } // 重写错误消息格式化方法,确保前后端错误消息一致 public override string FormatErrorMessage(string name) { var httpContext = HttpContext.Current; var localizer = httpContext?.GetService<IStringLocalizer<Language>>(); var localizedMessage = localizer?[_errorMessageKey] ?? "Passwords do not match."; return string.Format(localizedMessage, name); } }
方案二:继承原生CompareAttribute(更推荐)
和你写LocalizedStringLengthAttribute的思路一致,直接复用原生CompareAttribute的比较逻辑,只处理本地化,代码更简洁:
public class LocalizedCompareAttribute : CompareAttribute { public string ErrorMessageKey { get; set; } public LocalizedCompareAttribute(string otherProperty, string errorMessageKey) : base(otherProperty) { ErrorMessageKey = errorMessageKey; } public override string FormatErrorMessage(string name) { // 和你现有StringLength的写法保持一致,获取本地化服务 var httpContextAccessor = new HttpContextAccessor(); var localizer = httpContextAccessor.HttpContext?.RequestServices.GetService<IStringLocalizer<Language>>(); var localizedMessage = localizer?[ErrorMessageKey] ?? ErrorMessageString; // 这里可以根据你的资源文件格式,传入对应的参数(比如当前属性名、要比较的属性名) return string.Format(localizedMessage, name, OtherProperty); } }
最后再检查这几点:
- 确保你的
Language资源文件里,确实存在ConfirmPasswordErrorMessage这个键对应的本地化文本 - 视图里要启用验证:比如加上
@Html.ValidationSummary()和@Html.ValidationMessageFor(m => m.ConfirmPassword) - 检查类名拼写:别写成
LocalizedCompareAtribute(少个t)
备注:内容来源于stack exchange,提问作者Jakobik
相关产品推荐
相关产品推荐

