You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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);
    }
}

最后再检查这几点:

  1. 确保你的Language资源文件里,确实存在ConfirmPasswordErrorMessage这个键对应的本地化文本
  2. 视图里要启用验证:比如加上@Html.ValidationSummary()和@Html.ValidationMessageFor(m => m.ConfirmPassword)
  3. 检查类名拼写:别写成LocalizedCompareAtribute(少个t)

备注:内容来源于stack exchange,提问作者Jakobik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 11:28:08