When using Entity Framework with ASP.NET MVC, how to handle mandatory fields

asp.net-mvc asp.net-mvc-3 c# entity-framework validation

Question

Let me start out by describing my app in a step by step format.

First I have my Entity Framework generated model. Within it I have the following entities:

http://www.codetunnel.com/EFEntities.jpg

Now, to implement validation on an entity, I use partial classes and handle the OnChanging hooks that EF provides. Here is a sample of the PostComment partial class:

namespace CodeTunnel.Domain.Models
{
    public partial class PostComment : IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        partial void OnAuthorChanging(string value)
        {
            //Validating anything but required value works fine.
            //Like this pseudo-validator.
            if (value.ToLower() != "fred")
                _errors.Add("Author", "Sorry, your name must be Fred.");
        }

        partial void OnBodyChanging(string value)
        {
            //Required value validation does not work, I will tell you why below.
            if (string.IsNullOrEmpty(value))
                _errors.Add("Body", "Body is required.");
        }

        #region -= IDataErrorInfo methods =-

        public string Error
        {
            get { return string.Empty; }
        }

        public string this[string columnName]
        {
            get
            {
                if (_errors.ContainsKey(columnName))
                    return _errors[columnName];
                return string.Empty;
            }
        }

        #endregion
    }
}

Notice that my class inherits from IDataErrorInfo. MVC checks this for validation errors by default. If it finds any then it invalidates the model and uses the stored errors as the messages for the validation helpers in the view. I'm pretty sure when EF throws an exception, this dictionary never even gets populated with a value for that property. In fact, I'm not even sure that MVC goes so far as to look for a value after detecting and invalidating the model upon the EF generated exception.

Here is a screen shot of the problem, including the sample pseudo-validator so you can see it is working:

http://www.codetunnel.com/ValidationError.jpg

As you can see, the error message didn't show up. However, it did correctly validate the field as invalid. If I put a value in there then it validates just fine. I've done A LOT of research on this issue and here is what I know:

The reason you cannot customize the error message that is displayed for required fields is because the model property is not nullable. Because it is not nullable, trying to bind a null value to it throws an exception. MVC swallows this excepion and invalidates the model as it should. The message is generated wherever this exception occurs. I don't know if the message is generated by EF or MVC (I'm guessing MVC since it was responsible for swallowing the exception in the first place). I don't know how to customize this message. As you can see it always says "The value '' is invalid." which I suppose isn't totally horrible but it's really not very user-friendly.

It gets to my name validator and checks if your name is "fred" just fine because no exception is thrown. As far as EF is concerned the value passed in is fine. It isn't until it gets to my OnAuthorChanging method that it realizes it's not okay. This is the correct behavior and works just fine.

If I throw an exception in my OnChanging events instead of adding to my IDataErrorInfo dictionary I can generate the same validation message, only it puts the entered value between the single quotes. Example:

    partial void OnAuthorChanging(string value)
    {
        if (value.ToLower() != "fred")
            //_errors.Add("Author", "Sorry, your name must be Fred.");
            throw new Exception("Sorry, your name must be Fred.");
    }

That code shows this message when "test" is entered as the value for Author: "The value 'test' is invalid.". With the required fields it's just that the value is null so there is nothing to put between the single quotes.

Several people (like this guy) suggest that you simply set the property to nullable in your model. This is NOT an acceptable solution. One reason why not is this:

Error 3031: Problem in mapping fragments starting at line 313:Non-nullable column PostComments.Body in table PostComments is mapped to a nullable entity property.

Also, setting nullable simply will not work on non-nullable types such as int, and switching int to a nullable int is a yucky mess that I won't even get into here.

The bottom line is, I want to handle those exceptions from EF myself or at the very least customize the message it generates but I don't know how. I'm completely lost. All I want to do is customize a message on what I thought was very simple model validation!

1
7
10/13/2019 10:22:48 PM

Accepted Answer

MVC is validating your model based on the type being non nullible, as you have discovered. This is adding errors to ModelState before your custom validation runs.

I had this before, and got round it by looping through Modelstate at the start of an action and removing everything, then doing my custom validation (bad!!)

Then found even if you are not using data annotations as your main form of validation, you can customise the message that is thrown by adding [Required to the non nullible type in the buddy class, and specify the message.

It's something like this:

[MetadataType(typeof(YourClassMetadata))]
public partial class YourClass
{       
  //buddyclass to entity class
  class YourClassMetadata 
  {
    [Required(ErrorMessage="Your custom overriding error message")]
    public int NonNullablePropertyThatIsGivingYouProblems {get;set;}
  }
}

I've started to look at fluent validation (http://fluentvalidation.codeplex.com) for mvc, and they seem to turn off the problem in global.asax, in on application_start() by adding the line

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

but I may be wrong about that.

9
4/4/2013 10:55:46 AM

Popular Answer

I know its not exactly what you asked, but, I just finished a project last week in which i used MVC 3 Client Side Validation with Data Annotations and unobtrusive javascript. Its quite a mouthful, but works wonderful. You can setup regex, maxlenght, required, and all the other attributes, and it validates it all on the client. This makes form validation much faster for the user.

here are some useful links with examples, here, here and a very nice MSDN sample to download and try out here

hope it helps,



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow