如何为验证属性

时间:2016-11-24 13:48:00

标签: c# asp.net-core asp.net-core-mvc

我正在处理ASP.NET Core应用程序,我想覆盖数据注释的默认验证错误消息,例如RequiredMinLengthMaxLength等。我在以下网址阅读了文档:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization,它似乎没有涵盖我正在寻找的内容......

例如,Required属性的验证错误消息对于任何模型属性始终可以相同。默认文本只是声明: {0}字段是必需的,其中{0}占位符将填充属性的显示名称。

在我的视图模型中,我使用Required属性而没有任何命名参数,例如......

class ViewModel
{
    [Required, MinLength(10)]
    public string RequiredProperty { get; set; }
}

在我看来,设置ErrorMessageErrorMessageResourceName(以及ErrorMessageResourceType)是不必要的开销。我认为我可以实现与IDisplayMetadataProvider类似的东西,允许我返回应用属性的错误消息,以防验证失败。这可能吗?

4 个答案:

答案 0 :(得分:2)

如果要更改完整文本,则应使用资源文件对其进行本地化。

每个ValidationAttribute都有ErrorMessageResourceTypeErrorMessageResourceName的属性(请参阅来源here)。

[Required(ErrorMessageResourceName = "BoxLengthRequired", ErrorMessageResourceType = typeof(SharedResource))]

修改

好吧似乎有一种方法可以使用本地化提供程序对其进行本地化,但它仍然有点hacky并且要求属性上至少有一个属性(来自this blog post - 警告字虽然,它最初是用于旧的rc1或rc2版本,应该可以工作,但该文章中的某些API可能无效):

在启动时:

services.AddMvc()
   .AddViewLocalization()
   .AddDataAnnotationsLocalization();

在你的模特上:

[Required(ErrorMessage = "ViewModelPropertyRequired"), MinLength(10, ErrorMessage = "ViewModelMinLength")]
public string RequiredProperty { get; set; }

并实施/使用使用DB的本地化提供程序(即https://github.com/damienbod/AspNet5Localization)。

答案 1 :(得分:1)

对于那些到此为止的人,为了寻求通用解决方案,解决该问题的最佳方法是使用验证元数据提供程序。我的解决方案基于本文: AspNetCore MVC Error Message,我使用了.net框架样式的本地化,并将其简化为使用设计的提供程序。

  1. 将一个资源文件(例如 ValidationsMessages.resx )添加到您的项目中,并将访问修饰符设置为Internal或Public,以便生成背后的代码,该代码将为您提供 ResourceManager 静态实例。
  2. 为每种语言 ValidationsMessages。 es .resx 添加自定义本地化。请记住不要为此文件设置访问修饰符,代码是在步骤1上创建的。
  3. 添加 IValidationMetadataProvider
  4. 的实现
  5. 基于属性类型名称(例如“ RequiredAtrribute”)添加本地化。
  6. 在启动文件上设置您的应用。

示例验证消息。 es .resx

enter image description here

IValidatioMetadaProvider的示例:

using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
public class LocalizedValidationMetadataProvider : IValidationMetadataProvider
{
    public LocalizedValidationMetadataProvider()
    {
    }

    public void CreateValidationMetadata(ValidationMetadataProviderContext context)
    {
        if (context.Key.ModelType.GetTypeInfo().IsValueType && context.ValidationMetadata.ValidatorMetadata.Where(m => m.GetType() == typeof(RequiredAttribute)).Count() == 0)
            context.ValidationMetadata.ValidatorMetadata.Add(new RequiredAttribute());
        foreach (var attribute in context.ValidationMetadata.ValidatorMetadata)
        {
            var tAttr = attribute as ValidationAttribute;
            if (tAttr?.ErrorMessage == null && tAttr?.ErrorMessageResourceName == null)
            {
                var name = tAttr.GetType().Name;
                if (Resources.ValidationsMessages.ResourceManager.GetString(name) != null)
                {
                    tAttr.ErrorMessageResourceType = typeof(Resources.ValidationsMessages);
                    tAttr.ErrorMessageResourceName = name;
                    tAttr.ErrorMessage = null;
                }
            }
        }
    }
}

将提供程序添加到Startup类的ConfigureServices方法中:

services.AddMvc(options =>
{
    var F = services.BuildServiceProvider().GetService<IStringLocalizerFactory>();
    var L = F.Create("ModelBindingMessages", "EnGuate");
     options.ModelMetadataDetailsProviders.Add(new LocalizedValidationMetadataProvider());
})

答案 2 :(得分:0)

我遇到了同样的问题,我使用的解决方案是创建validation属性的子类以提供本地化的错误消息。

为了防止程序员意外使用非本地化版本,我只是省略了非本地化库的using语句。

答案 3 :(得分:0)

因此,由于创建了自己的自定义IStringLocalizer,我之所以来到这里,是因为@jlchavez帮助了我,我想分享我的解决方案。

我创建了一个MongoDB IStringLocalizer,并希望通过DataAnnotations使用资源。问题在于DataAnnotations属性期望通过公开资源的静态类进行本地化。

jlchavez's answer的一项增强是,它将为所有ValidationAttribute修复资源消息

services.AddTransient<IValidationMetadataProvider, Models.LocalizedValidationMetadataProvider>();
services.AddOptions<MvcOptions>()
    .Configure<IValidationMetadataProvider>((options, provider) =>
    {
        options.ModelMetadataDetailsProviders.Add(provider);
    });


public class Resource
{
    public string Id => Culture + "." + Name;
    public string Culture { get; set; }
    public string Name { get; set; }
    public string Text { get; set; }
}

public class MongoLocalizerFactory : IStringLocalizerFactory
{
    private readonly IMongoCollection<Resource> _resources;

    public MongoLocalizerFactory(IMongoCollection<Resource> resources)
    {
        _resources = resources;
    }

    public IStringLocalizer Create(Type resourceSource)
    {
        return new MongoLocalizer(_resources);
    }

    public IStringLocalizer Create(string baseName, string location)
    {
        return new MongoLocalizer(_resources);
    }
}

public class MongoLocalizer : IStringLocalizer
{
    private readonly IMongoCollection<Resource> _resources;

    public MongoLocalizer(IMongoCollection<Resource> resources)
    {
        _resources = resources;
    }

    public LocalizedString this[string name]
    {
        get
        {
            var value = GetString(name);
            return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
        }
    }

    public LocalizedString this[string name, params object[] arguments]
    {
        get
        {
            var format = GetString(name);
            var value = string.Format(format ?? name, arguments);
            return new LocalizedString(name, value, resourceNotFound: format == null);
        }
    }

    public IStringLocalizer WithCulture(CultureInfo culture)
    {
        CultureInfo.DefaultThreadCurrentCulture = culture;

        return new MongoLocalizer(_resources);
    }

    public IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures)
    {
        var resources = _resources.Find(r => r.Culture == CultureInfo.CurrentCulture.Parent.Name).ToList();
        return resources.Select(r => new LocalizedString(r.Name, r.Text, false));
    }

    private string GetString(string name)
    {
        var resource = _resources.Find(r => r.Culture == CultureInfo.CurrentCulture.Parent.Name && r.Name == name).SingleOrDefault();
        if (resource != null)
        {
            return new LocalizedString(resource.Name, resource.Text, false);
        }
        return new LocalizedString(name, name, true);
    }
}

public class LocalizedValidationMetadataProvider : IValidationMetadataProvider
{
    private IStringLocalizer _localizer;

    public LocalizedValidationMetadataProvider(IStringLocalizer localizer)
    {
        _localizer = localizer;
    }

    public void CreateValidationMetadata(ValidationMetadataProviderContext context)
    {
        foreach(var metadata in context.ValidationMetadata.ValidatorMetadata)
        {
            if (metadata is ValidationAttribute attribute)
            {
                attribute.ErrorMessage = _localizer[attribute.ErrorMessage].Value;
            }
        }
    }
}