Custom RegularExpressionAttribute missing data-val-regex-pattern for client-side validation
Asked Answered
E

2

6

I have created the following custom RegularExpressionAttribute

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class AlphaNumericAttribute: RegularExpressionAttribute, IClientValidatable
{
    public AlphaNumericAttribute()
      : base("^[-A-Za-z0-9]+$")
    {
    }

   public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
   {
      yield return new ModelClientValidationRule { ErrorMessage =  FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "alphanumeric" };
   }
}

The field in the ViewModel is decorated with my AlphaNumeric attribute:

[AlphaNumeric(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = Resources.DriverLicenseNumber_RegexError_)]
public string DriverLicenseNumber { get; set; }

The field is built in the view:

@using (Html.BeginForm("Index", "Application", FormMethod.Post, new { id = "applicationDataForm", autocomplete = "off" }))
{
    @Html.LabelFor(m => m.DriverLicenseNumber)
    @Html.ValidationMessageFor(m => m.DriverLicenseNumber)
    @Html.TextBoxFor(m => m.DriverLicenseNumber)
}

This should yield the proper "data-" validation attributes on my html input tag. However, the rendered tag looks like this:

<input data-val="true" data-val-alphanumeric="Please enter a valid driver's license number." id="DriverLicenseNumber" name="DriverLicenseNumber" type="text" value="" maxlength="20" class="valid">

Conspicuously absent are the data-val-regex and data-val-regex-pattern attributes that are supposed be rendered.

I have built other validators with the exact same structure, and they work correctly, like this SSN validation which handles masked spaces for a masked input using jquery masking:

public class SsnAttribute : RegularExpressionAttribute, IClientValidatable
{
  public SsnAttribute()
  : base("^([0-9]{3}–[0-9]{2}–[0-9]{4})|([ ]{3}–[ ]{2}–[ ]{4})|([0-9]{9,9})$")
{
}

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
  yield return new ModelClientValidationRule { ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), ValidationType = "ssn" };
}

}

With the accompanying application on the ViewModel:

[Ssn(ErrorMessageResourceType = typeof(Resources), ErrorMessageResourceName = Resources.SocialSecurity_RegexError_)]
public new string SocialSecurityNumber { get; set; }

The field is built in the view:

@using (Html.BeginForm("Index", "Application", FormMethod.Post, new { id = "applicationDataForm", autocomplete = "off" }))
{
    @Html.LabelFor(m => m.SocialSecurityNumber)
    @Html.ValidationMessageFor(m => m.SocialSecurityNumber)
    @Html.TextBoxFor(m => m.SocialSecurityNumber)
}

This validation attribute correctly renders the data-val-regex and data-val-regex-pattern attributes:

<input class="SSNMask valid" data-val="true" data-val-regex="Please enter a valid social security number." data-val-regex-pattern="^([0-9]{3}–[0-9]{2}–[0-9]{4})|([ ]{3}–[ ]{2}–[ ]{4})|([0-9]{9,9})$" id="SocialSecurityNumber" name="SocialSecurityNumber" type="text" value="" maxlength="22">



I cannot figure out what I am missing with the AlphaNumeric attribute that it does not render the appropriate html attributes.

Edieedification answered 30/7, 2013 at 20:20 Comment(2)
How/where in your view you are generating the corresponding input field? Are you using Html.TextBoxFor? Or Html.EditorFor? Is this call inside an Html.BeginForm? Could you please show your view?Teniacide
@Darin. I have updated my question to show the code from the view. I am using TextBoxFor with both the functional SSN validator and the non-functional AlphaNumeric validatorEdieedification
Z
10

I believe that your issue in case of AlphaNumericAttribute is that you did not added JavaScript adapter for your alphanumeric type of validator.

You surely have somehting like this in your code:

$.validator.unobtrusive.adapters.add('ssn', function(options) { /*...*/ });

Above code declares client side adapter for SsnAttribute. Note that it has name ssn which is the same as set in ValidationType property of ModelClientValidationRule.

To fix issue with AlphaNumericAttribute you should return ModelClientValidationRegexRule as it is already has all necessary setup for your case (i.e. already existing adapter regex).

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class AlphaNumericAttribute : RegularExpressionAttribute, IClientValidatable
{
    public AlphaNumericAttribute()
        : base("^[-A-Za-z0-9]+$")
    {
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRegexRule(FormatErrorMessage(metadata.GetDisplayName()), Pattern);
    }
}

But if there should be additional logic on client side behind the regex validation you should write and register your own unobtrusive adapter.

To get the bigger image and for better undestanding of how custom validation could be implemented in ASP.NET MVC you can reffer to the blog post of Brad Wilson Unobtrusive Client Validation in ASP.NET MVC 3, see Custom adapters for unusual validators section.

Zinovievsk answered 4/8, 2013 at 9:29 Comment(1)
I didn't actually do the JavaScript for the SsnAttribute as described since it automatically rendered and validated properly. However, the suggested fix of using ModelClientValidationRegexRule ( ) did fix my problem!Edieedification
R
1

Here's another approach from How to create custom validation attribute for MVC, which is adapted from this article on ASP.NET MVC Custom Validation:

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class AlphaNumericAttribute: RegularExpressionAttribute
{
    private const string pattern = "^[-A-Za-z0-9]+$";

    public AlphaNumericAttribute() : base(pattern)
    {
        // necessary to enable client side validation
        DataAnnotationsModelValidatorProvider.RegisterAdapter(
            typeof(AlphaNumericAttribute), 
            typeof(RegularExpressionAttributeAdapter));
    }
}

By using RegisterAdapter, you can leverage the integrations that already exist for regular expressions for your own inherited type.

Rentfree answered 21/1, 2015 at 1:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.