【问题标题】:ASP.NET Core custom validation error message not localizedASP.NET Core 自定义验证错误消息未本地化
【发布时间】:2022-01-04 19:38:25
【问题描述】:

我想在自定义属性中实现本地化,以检查该属性是否是有效的 IP 地址或主机名。到目前为止,验证工作正常,但我的问题是我只收到默认的英文错误消息,尽管我的本地已切换为德语。我正在处理资源文件。我不想为此实施客户端验证。我知道有办法实现适配器,但如果我错了,请纠正我,这仅用于客户端验证。

我的自定义验证类:

public class IPAddressOrHostnameAttribute : ValidationAttribute
{
     public IPAddressOrHostnameAttribute(string propertyName, object desiredvalue, string errorMessage)
    {
        PropertyName = propertyName;
        DesiredValue = desiredvalue;
        ErrorMessage = errorMessage;
    }

    private string PropertyName { get; }
    private object DesiredValue { get; }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        var instance = context.ObjectInstance;
        var type = instance.GetType();
        var propertyValue = type.GetProperty(PropertyName).GetValue(instance, null);
        if (propertyValue.ToString() == DesiredValue.ToString() && value != null)
        {
            if (Regex.IsMatch(value.ToString(), AckConstants.VALIDIPADDRESSREGEX)
                || Regex.IsMatch(value.ToString(), AckConstants.VALIDHOSTNAMEREGEX))
            {
                return ValidationResult.Success;
            }

            return new ValidationResult(ErrorMessage);
        }

        return ValidationResult.Success;
    }
}

我的模型类:

  [Required(ErrorMessage = "The field {0} is required")]
        [RegularExpression(@"^\S*$", ErrorMessage = "No white spaces allowed.")]
        [IPAddressOrHostname(nameof(IsFileAdapter), true, "Please enter a valid IP address or hostname")]
        [IPAddress(nameof(IsFileAdapter), false, "Please enter a valid IP address")]
        [Display(Name = "Destination")]
        public string Destination { get; set; }

我的启动类配置DataAnnotationLocalizerProvider:

services
                .AddMvc()
                .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix,
                    opts => { opts.ResourcesPath = "Resources"; })
                .AddDataAnnotationsLocalization(options =>
                {
                    options.DataAnnotationLocalizerProvider = (type, factory) =>
                        factory.Create(typeof(SharedResource)); // SharedResource is the class where the DataAnnotations (translations) will be stored.
                })

本地化适用于默认属性,例如Required 等,但不适用于我的自定义验证属性。我不知道我的代码有什么问题。我已经阅读了 ASP.NET Core custom validation attribute localization 的 stackoverflow 帖子,但我不明白为什么我的本地化服务器端验证不起作用。希望有人可以帮助我或给我一个如何让它工作的例子,因为这个问题让我发疯。

【问题讨论】:

    标签: asp.net-core custom-attributes asp.net-core-localization


    【解决方案1】:

    创建适配器可能是一种解决方案,但它太昂贵了!您必须创建适配器,然后创建适配器提供程序,然后您需要在启动时注册它!工作量太大了。

    更短的解决方案是通过ValidationContext.GetService 在自定义验证属性中获取本地化服务:

    如果您使用的是内置本地化服务,它将是 IStringLocalizer,如果您使用的是自定义本地化服务,例如(MyLocalizer) 您可以通过将其解析为GetService(typeof(MyLocalizer)) 方法来访问它。请参阅下面的示例:

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var _localizationService = (IStringLocalizer)validationContext.GetService(typeof(IStringLocalizer));
    
        var localizedError = _localizationService[ErrorMessage];
    
        //
        // do your custom validation
        //
        // if validation result is wrong
            return new ValidationResult(localizedError);
    
        // if validation result is correct
        return ValidationResult.Success;
    }
    

    顺便说一句,ValidationAttribute 已经有 ErrorMessage 属性,所以您不必在自定义属性中定义它。

    public IPAddressOrHostnameAttribute(string propertyName, object desiredvalue /*, string errorMessage*/)
        {
            PropertyName = propertyName;
            DesiredValue = desiredvalue;
            // ErrorMessage = errorMessage;
        }
    
    

    像其他属性一样使用它:

    [IPAddressOrHostname(nameof(IsFileAdapter), true, ErrorMessage = "Please enter a valid IP address or hostname")]
    

    【讨论】:

    • 感谢@Laz Ziya 非常感谢您的回答,这对我完成工作帮助很大。我正在使用 SharedResources。我不得不稍微延长你的线路,但现在它正在工作。 var localizationService = (IStringLocalizer) validationContext.GetService(typeof(IStringLocalizer<SharedResource>)); var localizedError = localizationService[ErrorMessage];
    • 就我而言,我必须这样做才能工作 - var _localizationService = (IStringLocalizer)validationContext.GetService(typeof(IStringLocalizer));
    【解决方案2】:

    我不想为此实施客户端验证。我知道有办法实现适配器,但如果我错了,请纠正我,这仅用于客户端验证。

    事实上,事实并非如此。适配器并不意味着您必须使用客户端验证。请参阅Ramin's answer here

    至于您的问题本身,您可以创建一个Adapter 和一个AdapterProvider 来提供适配器:

    public class IPAddressOrHostnameAttributeAdapter : AttributeAdapterBase<IPAddressOrHostnameAttribute>
    {
        public IPAddressOrHostnameAttributeAdapter(IPAddressOrHostnameAttribute attribute, IStringLocalizer stringLocalizer) 
            : base(attribute, stringLocalizer)
        { }
    
        public override void AddValidation(ClientModelValidationContext context) { }
    
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
        {
            return GetErrorMessage(validationContext.ModelMetadata, validationContext.ModelMetadata.GetDisplayName());
        }
    }
    
    public class  IPAddressOrHostnameAttributeAdapterProvider : IValidationAttributeAdapterProvider
    {
        private readonly IValidationAttributeAdapterProvider fallback = new ValidationAttributeAdapterProvider();
    
        public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
        {
            var attr = attribute as IPAddressOrHostnameAttribute;
            return attr == null?
                this.fallback.GetAttributeAdapter(attribute, stringLocalizer):
                new IPAddressOrHostnameAttributeAdapter(attr, stringLocalizer);
        }
    }
    

    另外,请确保此服务已在 DI 容器中注册:

    services.AddSingleton<IValidationAttributeAdapterProvider, IPAddressOrHostnameAttributeAdapterProvider>();
    

    最后,如果您使用查询字符串作为文化提供者,请不要忘记在表单操作中附加 culture=de

    @{ var __culture = Context.Features.Get<IRequestCultureFeature>().RequestCulture.Culture.ToString(); }
    
    <form asp-action="Create" asp-route-culture="@__culture">
        ....
    </form>
    

    演示截图

    【讨论】:

    • 感谢@itminus 为您提供快速解答。它也在工作:-)。两个正确答案你太棒了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 2017-04-11
    • 1970-01-01
    • 2023-03-13
    • 2016-07-23
    相关资源
    最近更新 更多