I already have some extended kind of RegularExpressionAttribute
implementation, that allows to use resources for regex pattern. It looks like:
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);
}
}
Also it's using ResourceAccessor
class to get regex out of resources
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));
}
}
}
And here is usage samples:
public class SignUpInput
{
[RegularExpressionEx("EmailValidationRegex", typeof(LocalizedResources), ErrorMessageResourceType = typeof(Messages), ErrorMessageResourceName = "invalidEmail")]
public string Email { get; set; }
}