How can I set a RegularExpression data annotation&

2019-01-23 04:57发布

问题:

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?

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


回答2:

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



回答3:

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



回答4:

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