How can I set a RegularExpression data annotation's regular expression argument at runtime?

Mark Bell picture Mark Bell · Dec 8, 2011 · Viewed 18.6k times · Source

We manage several ASP.NET MVC client web sites, which all use a data annotation like the following to validate customer email addresses (I haven't included the regex here, for readability):

[Required(ErrorMessage="Email is required")]
[RegularExpression(@"MYREGEX", ErrorMessage = "Email address is not valid")]
public string Email { get; set; }

What I would like to do is to centralise this regular expression, so that if we make a change to it, all of the sites immediately pick it up and we don't have to manually change it in each one.

The problem is that the regex argument of the data annotation must be a constant, so I cannot assign a value I've retrieved from a config file or database at runtime (which was my first thought).

Can anyone help me with a clever solution to this—or failing that, an alternative approach which will work to achieve the same goal? Or does this just require us to write a specialist custom validation attribute which will accept non-constant values?

Answer

Ian Routledge picture Ian Routledge · Dec 8, 2011

The easiest way is to write a custom ValidationAttribute that inherits from RegularExpressionAttribute, so something like:

public class EmailAttribute : RegularExpressionAttribute
    {
        public EmailAttribute()
            : base(GetRegex())
        { }

        private static string GetRegex()
        {
            // TODO: Go off and get your RegEx here
            return @"^[\w-]+(\.[\w-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?$";
        }
    }

That way, you still maintain use of the built in Regex validation but you can customise it. You'd just simply use it like:

[Email(ErrorMessage = "Please use a valid email address")]

Lastly, to get to client side validation to work, you would simply add the following in your Application_Start method within Global.asax, to tell MVC to use the normal regular expression validation for this validator:

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