我想在自定义属性中实现本地化,以检查该属性是否为有效的IP地址或主机名。到目前为止,验证工作正常,但是我的问题是,尽管我的本地语言切换为德语,但我仅收到默认的英语错误消息。我正在处理资源文件。我不想为此执行客户端验证。我知道有一种实现适配器的方法,但是如果我错了,请纠正我,这仅用于客户端验证。
我的自定义验证类:
[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
本地化适用于默认属性,例如kill(pid, SIGTERM)
等,但不适用于我的自定义验证属性。我不知道我的代码有什么问题。我已经阅读了ASP.NET Core custom validation attribute localization的stackoverflow帖子,但是我不明白为什么我的本地化服务器端验证无法正常工作。希望有人能帮助我或给我一个例子,让它正常工作,因为这个问题使我发疯。
答案 0 :(得分:0)
我不想为此执行客户端验证。我知道有一种实现适配器的方法,但是如果我错了,请纠正我,这仅用于客户端验证。
实际上,那不是事实。适配器并不意味着您必须使用客户端验证。请参阅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>();
最后,如果您使用querystring作为区域性提供程序,请不要忘记在表单操作中附加一个culture=de
:
@{ var __culture = Context.Features.Get<IRequestCultureFeature>().RequestCulture.Culture.ToString(); }
<form asp-action="Create" asp-route-culture="@__culture">
....
</form>
演示的屏幕截图
答案 1 :(得分:0)
创建适配器可能是一种解决方案,但这太昂贵了!您必须先创建适配器,然后创建适配器提供程序,然后在启动时进行注册!这是太多的工作。
一种较短的解决方案是通过ValidationContext.GetService
在自定义验证属性中获取本地化服务:
如果您使用内置的本地化服务,则使用IStringLocalizer
,如果您使用的是自定义本地化服务,例如(MyLocailzer),可以通过将其解析为GetService(typeof(MyLocaizer))
方法来访问它。参见以下示例:
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")]