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

19,366

Solution 1

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));

Solution 2

Checkout ScotGu's [Email] attribute (Step 4: Creating a Custom [Email] Validation Attribute).

Solution 3

Do you really want to put the regex in database/config file, or do you just want to centralise them? If you just want to put the regex together, you can just define and use constants like

public class ValidationRegularExpressions {
    public const string Regex1 = "...";
    public const string Regex2 = "...";
}

Maybe you want to manage the regexes in external files, you can write a MSBuild task to do the replacement when you build for production.

If you REALLY want to change the validation regex at runtime, define your own ValidationAttribute, like

[RegexByKey("MyKey", ErrorMessage = "Email address is not valid")]
public string Email { get; set; }

It's just a piece of code to write:

public class RegexByKeyAttribute : ValidationAttribute {
    public RegexByKey(string key) {
        ...
    }

    // override some methods
    public override bool IsValid(object value) {
        ...
    }
}

Or even just:

public class RegexByKeyAttribute : RegularExpressionAttribute {
    public RegexByKey(string key) : base(LoadRegex(key)) { }

    // Be careful to cache the regex is this operation is expensive.
    private static string LoadRegex(string key) { ... }
}

Hope it's helpful: http://msdn.microsoft.com/en-us/library/cc668224.aspx

Solution 4

Why not just write you own ValidationAttribute?

http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationattribute.aspx

Then you can configure that thing to pull the regex from a registry setting... config file... database... etc... etc..

How to: Customize Data Field Validation in the Data Model Using Custom

Share:
19,366
Mark Bell
Author by

Mark Bell

I'm a web developer based in Devon, UK.

Updated on June 03, 2022

Comments

  • Mark Bell
    Mark Bell about 2 years

    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?

  • Mark Bell
    Mark Bell over 12 years
    I'm accepting this because it was a simple, complete solution, explained well. Thanks!
  • Ian Routledge
    Ian Routledge over 12 years
    Thanks Mark and no worries, glad it helped!
  • Alan Shortis
    Alan Shortis over 10 years
    This is going back a while, but can someone explain just how they got their regex out of the resource file? I can get the expected languages in my my model (for the error message, for instance) but I always get the regular expression for the default .resx file from the extension when used above. Any ideas?
  • Ian Routledge
    Ian Routledge over 10 years
    Hi Alan, See msdn.microsoft.com/en-us/library/ms227982(v=vs.100).aspx which explains how to grab resource values programatically - you could use GetGlobalResourceObject in the GetRegex method to access your localised regex. Alternatively if you make Resources public (see holyhoehle.wordpress.com/2010/02/20/…) then you could just access Resource.Strings.SomeRegex etc.
  • Alan Shortis
    Alan Shortis over 10 years
    Thanks Ian. In my GetRegex method, I am passing in the value in my resx file as a parameter then returning the expression like this: return Resources.FormValidation.ResourceManager.GetString(value); It's mostly working, but I always get the value in my default resx file and never the one with a named culture. I have an open question here with more information (and maybe FIFTY points for you!): stackoverflow.com/questions/21735918/…