【问题标题】:Data Annotations - using an attribute extension and storing regular expressions in a resource file数据注释 - 使用属性扩展并将正则表达式存储在资源文件中
【发布时间】:2014-03-11 05:59:50
【问题描述】:

我目前正在使用 MVC4 数据注释来处理验证。我正在开发一个非常国际化的网站,因此我将所有文本都保存在资源文件中。

我还想在资源文件中保留用于验证的正则表达式,以便我可以使用相同的代码进行检查,例如,邮政编码(英国)邮政编码(美国)只需使用不同的 RegEx(以及不同名称的资源等)。

我有以下属性,它已经从资源文件中提取错误消息。我怎样才能让它也从资源文件中获取正则表达式?

[RegularExpression(@"^[\w]{1,2}[0-9]{1,2}[\w]?\s?[0-9]{1,2}[\w]{1,2}$", ErrorMessageResourceType = typeof(Resources.ValidationMessages), ErrorMessageResourceName = "validPostcode")]

编辑(再次)

我现在在哪里

按照下面的答案和一些额外的搜索,我有以下几点:

Global.asax.cs 中,我添加了以下行以确保调用客户端验证

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(LocalisedAttribute), typeof(RegularExpressionAttributeAdapter));

在我的模型中,我调用了属性扩展

[Localised(typeof(Resources.FormValidation), "postcodeRegEx", "postcodeMsg")]

最后,本地化正则表达式验证的属性扩展

public class LocalisedAttribute : RegularExpressionAttribute
{
    public LocalisedAttribute(Type resource, string regularExpression, string errorMessage) 
        : base(GetRegex(regularExpression))
    {
        ErrorMessageResourceType = resource;
        ErrorMessageResourceName = errorMessage;
    }

    private static string GetRegex(string value) 
    {
        return Resources.FormValidation.ResourceManager.GetString(value);


    }
}

这有效,但仅在我第一次在启动应用程序时使用它。

我将提出另一个问题来解决该问题 - 它与原始请求没有直接关系,似乎与大多数人的实施无关,并且似乎并不特定于数据注释。

【问题讨论】:

  • 你使用不同的 CultureInfos 吗?
  • 不,我不这么认为。
  • 我认为如果你想获得本地化资源,你必须决定从哪里获得文化信息名称并进行更改。

标签: asp.net asp.net-mvc asp.net-mvc-4 data-annotations custom-attributes


【解决方案1】:

我觉得你可以扩展RegularExpressionAttribute

public class PostCodeValidationAttribute : RegularExpressionAttribute
    {
        public PostCodeValidationAttribute()
            : base(Resources.PostCodeValidationExpression)
        {
        }
    }

更新

例如根据用户选择将文化信息名称放入会话中。并在

中使用它
ResourceManager.GetString(value, CultureInfo.CreateSpecificCulture(userCulture));

首先,您可以使用硬编码值对其进行测试。像这样的

ResourceManager.GetString(value, CultureInfo.CreateSpecificCulture("en-GB"));

改为

ResourceManager.GetString(value, CultureInfo.CreateSpecificCulture(currentCulture));

或在基础构造函数中

base(GetRegex(regularExpression, ""en-GB""))

【讨论】:

  • 感谢您的回答!我对 C# 相当陌生 - 我已经创建了上述属性,但不确定如何使用它。我已经用[PostCodeValidation] 替换了[RegularExpression(@...],但我不确定如何让它像以前一样工作。你能告诉我我需要在我的模型中添加什么吗?
  • 您是否使用正则表达式创建资源进行验证?你使用 CultureInfo 吗?
  • 我有带有正则表达式的资源文件,但此时我的正则表达式和错误消息作为扩展名中的字符串,以便我可以看到它工作。我会用一些代码更新我的问题...
  • 好的,问题已更新。我希望这是有道理的,并且我缺少一个明显的解决方案!
  • 我再次更新了我的答案 - 我现在遇到的问题是它没有为正则表达式使用正确的资源文件;它只从 defauklt resx 文件中检索表达式。
【解决方案2】:

我已经有了一些扩展的RegularExpressionAttribute 实现,它允许将资源用于正则表达式模式。它看起来像:

public class RegularExpressionExAttribute : RegularExpressionAttribute, IClientValidatable
{        
    private Regex regex { get; set; }
    private string pattern;

    private string resourceName;
    private Type resourceType;

    /// <summary>
    /// constructor, calls base with ".*" basic regex
    /// </summary>
    /// <param name="resName">resource key</param>
    /// <param name="resType">resource type</param>
    public RegularExpressionExAttribute(string resName, Type resType)
        : base(".*")
    {
        resourceName = resName;
        resourceType = resType;
    }

    /// <summary>
    /// override RegularExpressionAttribute property
    /// </summary>
    public new string Pattern
    {
        get
        {
            SetupRegex();
            return pattern;
        }
    }

    /// <summary>
    /// loads regex from resources
    /// </summary>
    private void SetupRegex()
    {
        ResourceAccessor ra = new ResourceAccessor(resourceName, resourceType);
        pattern = ra.resourceValue;
        regex = new Regex(pattern);
    }

    /// <summary>
    /// override validation with our regex
    /// </summary>
    /// <param name="value">string for validation</param>
    /// <returns></returns>
    public override bool IsValid(object value)
    {
        SetupRegex();
        string val = Convert.ToString(value);
        if (string.IsNullOrEmpty(val))
            return true;
        var m = regex.Match(val);
        return (m.Success && (m.Index == 0));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metaData, ControllerContext controllerContext)
    {
        yield return new ModelClientValidationRegexRule(base.ErrorMessageString, this.Pattern);
    }
}

它还使用ResourceAccessor 类从资源中获取正则表达式

public class ResourceAccessor
{
    private string resourceName;
    private Type resourceType;
    private Func<string> accessor;
    private string _resourceValue;

    public ResourceAccessor(string resourceName, Type resourceType)
    {
        this.resourceName = resourceName;
        this.resourceType = resourceType;
    }

    public string resourceValue
    {
        get
        {
            SetupAccessor();
            return accessor();
        }
    }

    private void SetupAccessor()
    {
        if (accessor != null) //already set
            return;
        string localValue = _resourceValue;
        bool flag1 = !string.IsNullOrEmpty(resourceName);
        bool flag2 = !string.IsNullOrEmpty(localValue);
        bool flag3 = resourceType != (Type)null;
        if (flag1 == flag2)
        {
            throw new InvalidOperationException("Can't set resource value");
        }
        if (flag3 != flag1)
        {
            throw new InvalidOperationException("Resource name and type required");
        }
        if (flag1)
            PropertyLookup();
        else
        {
            accessor = (Func<string>)(() => localValue);
        }
    }

    private void PropertyLookup()
    {
        if (resourceType == (Type)null || string.IsNullOrEmpty(resourceName))
        {
            throw new InvalidOperationException("Resource name and type required");
        }

        PropertyInfo property = resourceType.GetProperty(resourceName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
        if (property != (PropertyInfo)null)
        {
            MethodInfo getMethod = property.GetGetMethod(true);
            if (getMethod == (MethodInfo)null || !getMethod.IsAssembly && !getMethod.IsPublic)
                property = (PropertyInfo)null;
        }
        if (property == (PropertyInfo)null)
        {
            throw new InvalidOperationException("Resource type doesn't have property");
        }
        else if (property.PropertyType != typeof(string))
        {
            throw new InvalidOperationException("Resource type must be string");
        }
        else
        {
            accessor = (Func<string>)(() => (string)property.GetValue((object)null, (object[])null));
        }
    }
}

这里是使用示例:

public class SignUpInput
{        
    [RegularExpressionEx("EmailValidationRegex", typeof(LocalizedResources), ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "invalidEmail")]     
    public string Email { get; set; }
}

【讨论】:

  • 此解决方案以其当前形式运行。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-01-20
  • 1970-01-01
  • 2011-07-19
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
相关资源
最近更新 更多