trying to inherit RegularExpressionAttribute, no longer validates
Asked Answered
F

1

10

I'm trying to inherit the RegularExpressionAttribute to improve reusability with validating SSNs.

I have the following model:

public class FooModel
{
    [RegularExpression(@"^(?!000)(?!666)(?!9[0-9][0-9])\d{3}[- ]?(?!00)\d{2}[- ]?(?!0000)\d{4}$", ErrorMessage = "The SSN you entered is invalid. If you do not have this number please leave the field blank")]
    public string Ssn { get; set; }
}

which will validate correctly on the client and server. I wanted to encapsulate that lengthy regular expression into its own validation attribute like so:

public class SsnAttribute : RegularExpressionAttribute
{
    public SsnAttribute() : base(@"^(?!000)(?!666)(?!9[0-9][0-9])\d{3}[- ]?(?!00)\d{2}[- ]?(?!0000)\d{4}$")
    {
        ErrorMessage = "SSN is invalid";
    }
}

Then I changed my FooModel like so:

public class FooModel
{
    [Ssn(ErrorMessage = "The SSN you entered is invalid. If you do not have this number please leave the field blank")]
    public string Ssn { get; set; }
}

Now the validation doesn't render the unobtrusive data attributes on the client. I'm not quite sure as to why, since this seems like the two should essentially be the same thing.

Any suggestions?

Footboy answered 6/9, 2013 at 21:25 Comment(0)
S
19

In your Application_Start add the following line to associate an adapater to your custom attribute that will be responsible for emitting the client side validation attributes:

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

The reason why you need this is the way RegularExpressionAttribute is implemented. It doesn't implement IClientValidatable interface but it rather has a RegularExpressionAttributeAdapter which is associated to it.

In your case you have a custom attribute that derives from RegularExpressionAttribute but your attribute doesn't implement the IClientValidatable interface in order for client validation to work nor does it have an attribute adapter associated to it (contrary to its parent class). So your SsnAttribute should either implement the IClientValidatable interface or have an adapter associated as suggested previously in my answer.

This being said personally I don't see much point in implementing this custom validation attribute. A constant might be sufficient in this case:

public const string Ssn = @"^(?!000)(?!666)(?!9[0-9][0-9])\d{3}[- ]?(?!00)\d{2}[- ]?(?!0000)\d{4}$", ErrorMessage = "The SSN you entered is invalid. If you do not have this number please leave the field blank";

and then:

public class FooModel
{
    [RegularExpression(Ssn, ErrorMessage = "The SSN you entered is invalid. If you do not have this number please leave the field blank")]
    public string Ssn { get; set; }
}

seems quite readable.

Seigler answered 6/9, 2013 at 21:38 Comment(1)
I ended up having my attribute implement IClientValidatable. The reason I wanted an attribute for this instead of using a RegularExpressionAttribute was mainly because I didn't want to figure out where to put a public const string regex in my project (there are only two hard things in Computer Science...), but also because there seemed to be an emergin pattern from the MVC guys to create attributes that are basically no more than a RegularExpressionAttribute (PhoneAttribute', EmailAddressAttribute`, etc), so I felt justifiedFootboy

© 2022 - 2024 — McMap. All rights reserved.