using System.ComponentModel.DataAnnotations.Resources;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;
namespace System.ComponentModel.DataAnnotations
{
///
/// Regular expression validation attribute
///
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
[SuppressMessage("Microsoft.Performance", "CA1813:AvoidUnsealedAttributes", Justification = "We want users to be able to extend this class")]
public class RegularExpressionAttribute : ValidationAttribute
{
///
/// Gets the regular expression pattern to use
///
public string Pattern { get; private set; }
private Regex Regex { get; set; }
///
/// Constructor that accepts the regular expression pattern
///
/// The regular expression to use. It cannot be null.
public RegularExpressionAttribute(string pattern)
: base(() => DataAnnotationsResources.RegexAttribute_ValidationError)
{
this.Pattern = pattern;
}
///
/// Override of
///
/// This override performs the specific regular expression matching of the given
/// The value to test for validity.
/// true if the given value matches the current regular expression pattern
/// is thrown if the current attribute is ill-formed.
/// is thrown if the is not a valid regular expression.
internal override bool IsValid(object value)
{
this.SetupRegex();
// Convert the value to a string
string stringValue = Convert.ToString(value, CultureInfo.CurrentCulture);
// Automatically pass if value is null or empty. RequiredAttribute should be used to assert a value is not empty.
if (String.IsNullOrEmpty(stringValue))
{
return true;
}
Match m = this.Regex.Match(stringValue);
// We are looking for an exact match, not just a search hit. This matches what
// the RegularExpressionValidator control does
return (m.Success && m.Index == 0 && m.Length == stringValue.Length);
}
///
/// Override of
///
/// This override provide a formatted error message describing the pattern
/// The user-visible name to include in the formatted message.
/// The localized message to present to the user
/// is thrown if the current attribute is ill-formed.
/// is thrown if the is not a valid regular expression.
public override string FormatErrorMessage(string name)
{
this.SetupRegex();
return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, this.Pattern);
}
///
/// Sets up the property from the property.
///
/// is thrown if the current cannot be parsed
/// is thrown if the current attribute is ill-formed.
private void SetupRegex()
{
if (this.Regex == null)
{
if (string.IsNullOrEmpty(this.Pattern))
{
throw new InvalidOperationException(DataAnnotationsResources.RegularExpressionAttribute_Empty_Pattern);
}
this.Regex = new Regex(this.Pattern);
}
}
}
}