ASP.NET Core 自定义验证属性本地化

问题描述 投票:0回答:4

我正在尝试在 asp.net core 1.0 的自定义验证属性中实现本地化。这是我的简化视图模型:

public class EditPasswordViewModel
{
    [Required(ErrorMessage = "OldPasswordRequired")]
    [DataType(DataType.Password)]
    [CheckOldPassword(ErrorMessage = "OldPasswordWrong")]
    public string OldPassword { get; set; }
}

“OldPasswordRequired”的本地化工作正常。但是,我的自定义属性的本地化不起作用,并且始终返回“OldPasswordWrong”消息。这是代码:

public class CheckOldPasswordAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object classInstance, ValidationContext validationContext)
    {                   
        if (oldPasswordSaved == oldPasswordTyped) //simplified
        {
            return ValidationResult.Success;
        }
        else
        {
            string errorMessage = FormatErrorMessage(ErrorMessageString);
            return new ValidationResult(errorMessage);
        }
    }

}

ErrorMessageString 始终为“OldPasswordWrong”,FormatErrorMessage 始终返回“OldPasswordWrong”。我究竟做错了什么? 我正在使用新的 asp.net 核心数据注释本地化,所以我没有使用 ErrorMessageResourceName 和 ErrorMessageResourceType 属性(我没有任何 ViewModel.Designer.cs)。

c# asp.net-core localization asp.net-core-mvc
4个回答
28
投票

实现本地化适配器:

public class RequiredIfAttributeAdapter : AttributeAdapterBase<RequiredIfAttribute>
{
    public RequiredIfAttributeAdapter(RequiredIfAttribute 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 CustomValidationAttributeAdapterProvider : IValidationAttributeAdapterProvider
{
    private readonly IValidationAttributeAdapterProvider _baseProvider = new ValidationAttributeAdapterProvider();

    public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute, IStringLocalizer stringLocalizer)
    {
        if (attribute is RequiredIfAttribute)
            return new RequiredIfAttributeAdapter(attribute as RequiredIfAttribute, stringLocalizer);
        else
            return _baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
    }
}

在 Startup.cs 中注册提供者:

services.AddSingleton<IValidationAttributeAdapterProvider, CustomValidationAttributeAdapterProvider>();

此博客的致谢:https://blogs.msdn.microsoft.com/mvpawardprogram/2017/01/03/asp-net-core-mvc/


6
投票

Ramin 的答案是正确答案。但是我决定走另一条路,所以我不必为很多情况编写适配器和适配器提供程序。

想法是将您的特定字符串定位器包装在服务接口中,并从验证属性本身获取它。

public class CPFAttribute: ValidationAttribute
{
    public CPFAttribute()
    {
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string cpf;

        try
        {
            cpf = (string)value;
        }
        catch (Exception)
        {
            return new ValidationResult(GetErrorMessage(validationContext));
        }

        if (string.IsNullOrEmpty(cpf) || cpf.Length != 11 || !StringUtil.IsDigitsOnly(cpf))
        {
            return new ValidationResult(GetErrorMessage(validationContext));
        }

        return ValidationResult.Success;
    }

    private string GetErrorMessage(ValidationContext validationContext)
    {
        if (string.IsNullOrEmpty(ErrorMessage))
        {
            return "Invalid CPF";
        }

        ErrorMessageTranslationService errorTranslation = validationContext.GetService(typeof(ErrorMessageTranslationService)) as ErrorMessageTranslationService;
        return errorTranslation.GetLocalizedError(ErrorMessage);
    }
}

然后服务可以创建为:

public class ErrorMessageTranslationService
{
    private readonly IStringLocalizer<SharedResource> _sharedLocalizer;
    public ErrorMessageTranslationService(IStringLocalizer<SharedResource> sharedLocalizer)
    {
        _sharedLocalizer = sharedLocalizer;
    }

    public string GetLocalizedError(string errorKey)
    {
        return _sharedLocalizer[errorKey];
    }
}

该服务可以在 Startup 类中注册为单例。

services.AddSingleton<ErrorMessageTranslationService>();

如果这些验证属性需要分解到另一个程序集,只需为此翻译服务创建一个接口,您创建的所有验证属性都可以引用该接口。


0
投票

Marcos的答案有一点偏差,如果您在

Asp.Net Core
AddDataAnnotationsLocalization()
中使用
program.cs
以及
startup.cs
方法:
您可以通过以下方式获取定位器:

sealed public class MyCustomValidationAttribute : ValidationAttribute
{
    private static IStringLocalizer localizer;

    //...
    protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
    {
        //...
        return new ValidationResult(GetErrorMessage(validationContext));
        //...
    }

    private string GetErrorMessage(ValidationContext validationContext)
    {
        //...
        return GetLocalizer(validationContext)[ErrorMessage];
    }

    private IStringLocalizer GetLocalizer(ValidationContext validationContext)
    {
        if (localizer is null)
        {
            var factory = validationContext.GetRequiredService<IStringLocalizerFactory>();
            var annotationOptions = validationContext.GetRequiredService<IOptions<MvcDataAnnotationsLocalizationOptions>>();
            localizer = annotationOptions.Value.DataAnnotationLocalizerProvider(validationContext.ObjectType, factory);
        }

        return localizer;
    }

    //...
}

删除 Marcos 的答案类中提到的

ErrorMessageTranslationService
并使用
GetLocalizer()
来获取用于在整个项目中本地化其他正常注释的
LocalizedString


-1
投票

您需要指定文化。 formaterrormesage 会做什么?它会处理文化吗?

检查此链接

© www.soinside.com 2019 - 2024. All rights reserved.