January 2018 : Instructor-led Online Course in ASP.NET Core 2.0. Conducted by Bipin Joshi. Read more...
Registration for January 2018 batch of ASP.NET Core 2.0 instructor-led online course has already started. Conducted by Bipin Joshi. Register today ! Click here for more details.

Validate Model Programmatically in ASP.NET MVC

 ASP.NET model binding framework takes care of validating a model based on data annotation validations. This works well when a model is being bound with request data. However, at times you may need to create and fill a model programmatically. In such cases, although the model properties are decorated with data annotation validators, they won't validate the data because they are not invoked at all. Consider a situation wherein users are uploading CSV files from the client machine on to the server. Your application is supposed to read those files and assign the values from the file to the model properties. The model objects are then stored to some database. In this case data validations won't fire and your model will be held in an invalid state. Since model validations are not being invoked ModelState.IsValid will always return true and there won't be any easy way to detect and display these validation failures. Luckily, ASP.NET MVC allows you to validate a model object via code. This article shows how.

Let's assume that you have a UserInfo model class as shown below:

public class UserInfo
{
    [Required]
    [StringLength(100, MinimumLength = 10)]
    public string FirstName { get; set; }

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

    [Required]
    public DateTime BirthDate { get; set; }
}

The UserInfo class consists of three properties - FirstName, LastName and BirthDate. All the model properties are decorated with [Required] attribute. Additionally, FirstName and LastName properties are decorated with [StringLength] attribute. Both of these properties also have MinimumLength set to 10 just for the sake of testing.

Now consider a view (Index.cshtml) as shown below:

The Index view shown above consists of a file upload control and a button. You are supposed to select a CSV file that contains data suitable for UserInfo model. Upon selecting a CSV file and clicking the Upload button success or error message will be displayed in another view (UploadResult.cshtml). A sample CSV file would look like this:

Nancy,Davolio,1/2/1960

The HTML markup that makes Index.cshtml is shown below:

<h1>Select file to be uploaded:</h1>
<form action="/home/savedata" method="post" 
enctype="multipart/form-data">
    <input type="file" name="file1" />
    <input type="submit" value="Upload" />
</form>

The <form> posts the file to SaveData() action method. The SaveData() action does the job of reading the uploaded file, instantiating a model object, setting model properties and then displaying UploadResult view with a success or error message. For example, the following figure shows UploadResult view when the UserInfo model is in invalid state:

Notice that the UploadResult view displays validation errors through ValidationSummary() helper.

Now let's see the most important part of the application - SaveData() action method.

public ActionResult SaveData()
{
  if(Request.Files.Count>0)
  {
    HttpFileCollectionBase files = Request.Files;
    foreach(string key in Request.Files)
    {
     HttpPostedFileBase item = Request.Files[key];
     byte[] data = new byte[item.InputStream.Length];
     int byteCount = item.InputStream.Read(data, 0, data.Length);
     string strData = ASCIIEncoding.UTF8.GetString(data).Trim();
     string[] values = strData.Split(',');

     UserInfo info = new UserInfo();
     info.FirstName = values[0];
     info.LastName = values[1];
     info.BirthDate = DateTime.Parse(values[2]);

     if(TryValidateModel(info))
     {
       //save in database here
       ViewBag.Message = "User information is 
                     validated successfully!";
     }
     else
     {
       ViewBag.Message = "Error while validating user info. 
           Please review the errors below 
           and upload the file again!";
     }
     return View("UploadResult", info);
   }
 }
 return View("Index");
}

The SaveData() action iterates through the Request.Files collection and gets hold of the file being uploaded. In our example it is assumed that only one will be uploaded. You don't need to save this file on the server because your interest is in the CSV data in the file. That's why the code reads the content of InputStream of the file using Read() method. The Read() method reads the content in a byte array. This byte array is converted into a string using GetString() method of the ASCIIEncoding class. The string data is further split into a string array using Split() method.

Notice the code marked in bold letters. The code creates a UserInfo object and assigns FirstName, LastName and BirthDate properties from the string array created earlier. If you see the sample data shown earlier you will realize that FirstName and LastName doesn't meet the requirement of [StringLength] attribute. However, at this stage ModelState.IsValid will be true because data validations are not invoked yet.

Next, the code uses TryValidateModel() method that invokes the data validations. There are two variations of this method - ValidateModel() and TryValidateModel(). Both of them come from the Controller base class. The former method throws an exception if there are any validation errors whereas the later method silently returns false in case validations fail. If you check ModelState.IsValid after the call to TryValidateModel() you will see that it returns false because there are validation errors.

The SaveData() action sends UserInfo model object to the UploadResult view so that validation errors can be displayed. The UploadResult view contains this HTML markup:

@model StProcInCodeFirstDemo.Models.UserInfo
...
<body>
    @ViewBag.Message
    <br /><br />
    @Html.ValidationSummary()
    <br /><br />
    @Html.ActionLink("Upload again!","Index")
</body>
...

Notice that UploadResult view uses ValidateSummary() helper to display the validation error messages. As you might be aware ValidationSummary() or ValidationMessage() helpers work only if ModelState dictionary contains some entries. In our example these entries are added by TryValidateModel() method. Since ModelState dictionary contains some entries the ValidationSummary() iterates through them and displays the validation errors.

That's it! Try running the application a couple of times with invalid as well as valid data and see if everything works as expected.


Bipin Joshi is a software consultant, an author and a yoga mentor having 22+ years of experience in software development. He also conducts online courses in ASP.NET MVC / Core and Design Patterns. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Meditation and Mindfulness to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 24 December 2014


Tags : ASP.NET MVC C# Visual Studio