TOC

The community is working on translating this tutorial into Croatian, but it seems that no one has started the translation process for this article yet. If you can help us, then please click "More info".

Models:

Model Validation

In the previous article, we talked about DataAnnotations and how they can enrich your Models to work even tighter together with your Views. However, a lot of the available DataAnnotations are actually directly related to the validation mechanisms found in the ASP.NET MVC framework. They will allow you to enforce various kinds of rules for your properties, which will be used in your Views and in your Controllers, where you will be able to check whether a certain Model is valid in its current state or not (e.g. after a FORM submission).

Adding basic validation

Just like we saw in the previous article, validation rules can be applied to properties through the use of DataAnnotations. There are several types available, but for now, we'll add just a couple of them to the WebUser class previously introduced:

public class WebUser  
{  
    [Required]
    [StringLength(25)]
    public string FirstName { get; set; }

    [Required]
    [StringLength(50, MinimumLength = 3)]
    public string LastName { get; set; }

    [Required]
    [EmailAddress]
    public string MailAddress { get; set; }
}

Notice how the three properties have all been decorated with DataAnnotations, giving the framework useful information for validating the data. First of all, all properties have been marked with the [Required] attribute, meaning that a value is required - it can't be NULL. We have also used the [StringLength] attribute to make requirements about the maximum, and in one case minimum, length of the strings. These are of course particularly relevant if your Model corresponds to a database table, where strings are often defined with a maximum length. For the last property, we have used the [EmailAddress] attribute to ensure that the value provided looks like an e-mail adress.

To test this example, let's create a simple FORM for it. We'll use Model Binding, as described in a previous article, to generate the fields for the properties:

@model HelloMVCWorld.Models.WebUser
@using(var form = Html.BeginForm())
{
    <div>
@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName)
    </div>

    <div>
@Html.LabelFor(m => m.LastName)
@Html.TextBoxFor(m => m.LastName)
    </div>

    <div>
@Html.LabelFor(m => m.MailAddress)
@Html.TextBoxFor(m => m.MailAddress)
    </div>

    <input type="submit" value="Submit" />
}

Now we just need a Controller to serve the View, as well as handle the POST request when the FORM is submitted:

public class ValidationController : Controller
{
    [HttpGet]
    public IActionResult SimpleValidation()
    {
return View();
    }

    [HttpPost]
    public IActionResult SimpleValidation(WebUser webUser)
    {
if(ModelState.IsValid)
    return Content("Thank you!");
else
    return Content("Model could not be validated!");
    }

}

The interesting part here is of course the POST action, where we check the IsValid property of the ModelState object. Depending on the data you submitted in the FORM, it will be either true or false, based on the validation rules we defined for the Model (WebUser). With this in place, you can now prevent a Model from being saved, e.g. to a database, unless it's completely valid.

Displaying validation errors

In the above example, we can now see whether a Model is valid or not, thanks to the validation rules we have added to the Model. But it would obviously be way more useful if we could show these problems to the end-user, so that they could be fixed. Fortunately for us, that's really easy!

First of all, we need to extend our FORM so that it can display error messages to the user. We can use another helper method found on the Html object: The ValidationMessageFor() method. It will simply output the error message related to the field, if there is one - otherwise, nothing will be outputted. Here's the extended version of our FORM:

@model HelloMVCWorld.Models.WebUser
@using(var form = Html.BeginForm())
{
    <div>
@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName)
@Html.ValidationMessageFor(m => m.FirstName)
    </div>

    <div>
@Html.LabelFor(m => m.LastName)
@Html.TextBoxFor(m => m.LastName)
@Html.ValidationMessageFor(m => m.LastName)
    </div>

    <div>
@Html.LabelFor(m => m.MailAddress)
@Html.TextBoxFor(m => m.MailAddress)
@Html.ValidationMessageFor(m => m.MailAddress)
    </div>

    <input type="submit" value="Submit" />
}

We also need to make sure that once the FORM is submitted, and if there are validation errors, we return the FORM to the user, so that they can see and fix these errors. We do that in our Controller, simply by returning the View and the current Model state, if there are any validation errors:

[HttpPost]
public IActionResult SimpleValidation(WebUser webUser)
{
    if(ModelState.IsValid)
return Content("Thank you!");
    else
return View(webUser);
}

With that in place, try submitting the FORM with empty fields. You should be immediately returned to the FORM, but with validation messages next to each of the fields, thanks to the [Required] attribute:

If you try submitting the FORM with a value that doesn't meet the StringLength requirements, you will notice that there are even automatically generated error messages for these as well. For instance, if you submit the FORM with a LastName that's either too long or too short, you will get this message:

The field LastName must be a string with a minimum length of 3 and a maximum length of 50.

But what if you want more control of these messages? No problem, they can be overridden directly in the DataAnnotations of the Model. Here's a version of our Model where we have applied custom error messages:

public class WebUser  
{  
    [Required(ErrorMessage = "You must enter a value for the First Name field!")]  
    [StringLength(25, ErrorMessage = "The First Name must be no longer than 25 characters!")]  
    public string FirstName { get; set; }  

    [Required(ErrorMessage = "You must enter a value for the Last Name field!")]  
    [StringLength(50, MinimumLength = 3, ErrorMessage = "The Last Name must be between 3 and 50 characters long!")]  
    public string LastName { get; set; }  

    [Required(ErrorMessage = "You must enter a value for the Mail Address field!")]  
    [EmailAddress(ErrorMessage = "Please enter a valid e-mail address!")]  
    public string MailAddress { get; set; }  
}

So as you can see, it's really easy to customize the error messages!

Displaying a validation summary

An individual error message for each input field can be really useful, especially if you have a large FORM. However, for smaller forms, like the one in our example, it might be more useful to simply display a summary of the validation errors, either above or below all the fields. That's easily accomplished, thanks to the ValidationSummary() method found on the Html helper object:

@model HelloMVCWorld.Models.WebUser
@using(var form = Html.BeginForm())
{
    @Html.ValidationSummary()
   
    <div>
@Html.LabelFor(m => m.FirstName)
@Html.TextBoxFor(m => m.FirstName)        
    </div>

    <div>
@Html.LabelFor(m => m.LastName)
@Html.TextBoxFor(m => m.LastName)        
    </div>

    <div>
@Html.LabelFor(m => m.MailAddress)
@Html.TextBoxFor(m => m.MailAddress)        
    </div>

    <input type="submit" value="Submit" />
}

Now, when the FORM is submitted and returned with validation errors, it will look like this instead:

Of course, you can combine the per-field validation message approach with a validation summary, if you feel like it.

Summary

Adding basic Model Validation is very easy and will help ensure that user-provided information matches the requirements you may have for the data. As mentioned, these are just some of the validation options available in the ASP.NET MVC framework. In the next article, we'll look into the rest of them!


This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!