By UserControl


2011-06-22 08:42:25 8 Comments

If i have [Required(AllowEmptyStrings = true)] declaration in my view model the validation is always triggered on empty inputs. I found the article which explains why it happens. Do you know if there is a fix available? If not, how do you handle it?

2 comments

@Jon Galloway 2011-06-27 20:50:30

Note: I'm assuming you have AllowEmptyStrings = true because you're also using your view model outside of a web scenario; otherwise it doesn't seem like there's much of a point to having a Required attribute that allows empty strings in a web scenario.

There are three steps to handle this:

  1. Create a custom attribute adapter which adds that validation parameter
  2. Register your adapter as an adapter factory
  3. Override the jQuery Validation function to allow empty strings when that attribute is present

Step 1: The custom attribute adapter

I modified the RequiredAttributeAdapter to add in that logic:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace CustomAttributes
{
    /// <summary>Provides an adapter for the <see cref="T:System.Runtime.CompilerServices.RequiredAttributeAttribute" /> attribute.</summary>
    public class RequiredAttributeAdapter : DataAnnotationsModelValidator<RequiredAttribute>
    {
        /// <summary>Initializes a new instance of the <see cref="T:System.Runtime.CompilerServices.RequiredAttributeAttribute" /> class.</summary>
        /// <param name="metadata">The model metadata.</param>
        /// <param name="context">The controller context.</param>
        /// <param name="attribute">The required attribute.</param>
        public RequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, RequiredAttribute attribute)
            : base(metadata, context, attribute)
        {
        }
        /// <summary>Gets a list of required-value client validation rules.</summary>
        /// <returns>A list of required-value client validation rules.</returns>
        public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
        {
            var rule = new ModelClientValidationRequiredRule(base.ErrorMessage);
            if (base.Attribute.AllowEmptyStrings)
            {
                //setting "true" rather than bool true which is serialized as "True"
                rule.ValidationParameters["allowempty"] = "true";
            }

            return new ModelClientValidationRequiredRule[] { rule };
        }
    }
}

Step 2. Register this in your global.asax / Application_Start()

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(typeof(RequiredAttribute),
          (metadata, controllerContext, attribute) => new CustomAttributes.RequiredAttributeAdapter(metadata,
            controllerContext, (RequiredAttribute)attribute)); 

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }

Step 3. Override the jQuery "required" validation function

This is done using the jQuery.validator.addMethod() call, adding our custom logic and then calling the original function - you can read more about this approach here. If you are using this throughout your site, perhaps in a script file referenced from your _Layout.cshtml. Here's a sample script block you can drop in a page to test:

<script>
jQuery.validator.methods.oldRequired = jQuery.validator.methods.required;

jQuery.validator.addMethod("required", function (value, element, param) {
    if ($(element).attr('data-val-required-allowempty') == 'true') {
        return true;
    }
    return jQuery.validator.methods.oldRequired.call(this, value, element, param);
},
jQuery.validator.messages.required // use default message
);
</script>

@UserControl 2011-06-28 10:12:23

Thanks for your efforts, Jon! Unfortunately it's not working for me, i still see "field is required" message :( I double checked that your code is executed with VS and browser debuggers and i don't have any custom scripts or validation related code that might interfere. I use jQuery 1.4.1. Can this be the problem?

@UserControl 2011-06-28 10:15:13

And yes, you're right that i need the feature outside of web scenarios (my application service layer performs similar validation checks to be DRY).

@Tz_ 2011-06-28 21:36:06

+1 This seems to be a nice solution, I wonder why it does not work. But maybe you could simplify it, if you return no validation rule (empty array) in the adapter in case of AllowEmptyStrings. You could then spare the client side magic. You could then also easily check if the required attribute is correctly omitted on your input. If it still does not work, you should debug the adapter code and see if it is called appropriately (if the registration is ok).

@Jon Galloway 2011-06-28 23:54:57

This has the "works on my machine" pledge ;-) The script block I listed is immediately after the calls to /Scripts/jquery.validate.js and /Scripts/jquery.validate.unobtrusive.js. I am using a new MVC 3 project with jQuery 1.5.1. I'll try to post the sample project so you can compare.

@Jon Galloway 2011-07-01 16:41:59

I'm curious - what wasn't working? Was it a Javascript reference?

@Dave 2013-08-22 20:00:10

In case anyone comes on this late like I did, I'll point out that if you can create a metadata class using [DisplayFormat(ConvertEmptyStringToNull=false)] for the property, and leave the database field as required, then the user can leave the field blank, and have it get passed in as empty string, but if a null gets put in the field some other way, the model still won't validate on insert/update.

@Roberto Bonini 2014-09-25 14:26:42

Hi Jon - Can we use something similar for EF code first fields that use the Required Attribute?

@Rick Arthur 2013-09-09 07:02:42

Rather than decorating the value with the 'Required' attribute, I use the following. I find it to be the simplest solution to this issue.

[DisplayFormat(ConvertEmptyStringToNull=false)]

@Andy White 2013-12-04 19:13:54

I agree - this seems to be the easiest way to deal with this. If you want to allow empty strings, just change the null back to "" in the controller before saving!

@Mark Rucker 2015-10-21 14:55:07

Beautiful! This draw back of [Required] has irked me for years on multiple asp.net websites.(I'm now using both [Required(AllowEmptyStrings = true), DisplayFormat(ConvertEmptyStringToNull=false)] and it works great.

@AH. 2015-12-03 09:44:57

Great answer. Thanks a lot.

@Patrick 2016-02-16 20:38:17

+10 to both Rick & Mark for easing the MVC empty string pain, using both DisplayFormat(ConvertEmptyStringToNull=false) & Required(AllowEmptyStrings = true)

Related Questions

Sponsored Content

41 Answered Questions

[SOLVED] A comprehensive regex for phone number validation

33 Answered Questions

[SOLVED] (Built-in) way in JavaScript to check if a string is a valid number

73 Answered Questions

49 Answered Questions

[SOLVED] Validate decimal numbers in JavaScript - IsNumeric()

21 Answered Questions

[SOLVED] File Upload ASP.NET MVC 3.0

8 Answered Questions

[SOLVED] Email address validation using ASP.NET MVC data type attributes

11 Answered Questions

[SOLVED] jQuery Validate Required Select

5 Answered Questions

12 Answered Questions

[SOLVED] ASP.NET MVC Conditional validation

7 Answered Questions

[SOLVED] Entity Framework 5 Updating a Record

Sponsored Content