Friday, 22 July 2011

MVC3 JQuery Client Validation using Entity Model Framework 4.1 auto generated classes

Hi all,

This is a quick tutorial on how to perform client validation using the MVC framework with auto generated classes in the backend. You might have these auto-generated classes by using a data modelling framework such as: Entity Framework or Linq-To-Sql.

Prerequisites
Creating an MVC 3 Web Application with the Razor View Engine, HTML5 and IIS Express 7.5


Creating an entity model using EMF 4.1
1. Create a new Entity Data Model (.edmx) file within your Modules folder. Right click Modules and add a "ADO.NET Entity Data Model" item. Call this "MembershipModel.edmx"
2. If you have a database already, seelct "Generate from database". This will automatically create entities based on your tables. If not, select "Empty model".
3. Open the entity designer file (.edmx).
4. If you selected "Empty model", Right click the designer > Add > Entity...
5. Name the entity "User"
6. OK to create!
7. Right click the new entity > Add > Scalar Property
8. Call the property "Name"
9. Right click the new entity > Add > Scalar Property
10. Call the property "Email"
11. You can generate your database from your model. Once you have created your entities, right click the designer and select "Generate Database from Model". Don't worry if you need to update these at a later date, EMF does a good job of syncing these later.
12. Setup a new connection to your database
13. You will be presented with an SQL script for your entities, cool huh?
14. Execute this against your datastore.

Note: If you open the designer oce behind file (MembershipModel.Designer.cs), you can see that the classes have been created for us (one per entity), aswell as some properties and a method to create a new user (in our example). By default, the designer uses a code generater called T4 (Text Template Transformation Toolkit). You will notice that all classes using the default template implement the EntityObject base class. These classes provide a lot of functionality, but are quite cumbersome to work with. So we are going to use a different generator! (DbContext Generator)


Using the DbContext Generator
1. Right click the Entity Model .edmx designer > "Add Code generation"
2. Select "ADO.NET DbContext Generator" from the dialog and name it "Model1.tt".
3. OK to create!
4. You will receive a warning because template can potentially contain harmful content. Just click ok!

Note: You will notice that two files have been created under the Models folder: Model1.tt and Model1.Context.tt. Underneath the Model1.tt file, you will be a custom class representing your entity "User.cs". This is the class you will be using throughout this sample application to represent users! If you don't see this class here, then you have created your database!



ok, im a master at EMF, show me the validation already!

With MVC, a simple way to perform validation is to use the [Required] atrribute for properties of our class. Now the problem lies with the way our classes are generated by the code generator (We cannot change the designer fiels because we'll lose our changes, plus its stupid!). An easy way around this is to use Metadatatype!

Metadatatype and T4 class validation
1. Right click the Models folder > Add > Class..
2. Call it "UserValidation.cs"
3. Enter the following code...

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
 
namespace MvcApplication1.Models
{
    [MetadataType(typeof(UserValidation))]
    public partial class User
    {}
 
    public class UserValidation
    {
        [Required(ErrorMessage = "Your Full Name is required")]
        public string Name { get; set; }
 
        [Required(ErrorMessage = "Your Email Address is required")]
        [RegularExpression(@"^[\w-]+(\.[\w-]+)*@([a-z0-9-]+(\.[a-z0-9-]+)*?\.[a-z]{2,6}|(\d{1,3}\.){3}\d{1,3})(:\d{4})?$", ErrorMessage = "Your Email Address is invalid")]
        public string Email { get; set; }
    }
}



Note: You will notice that Metadatatype allows us to specify another class on behalf of an existing partial class, to append attribues to. These attributes will be our validation attributes! I have chosen the Name and the Email properties of our user entity to apply validation to.


Configuring the Controller
1. Add a new controller. I.e. HomeController
2. In the Index method, return the view with a new copy of the EMF generated User class.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using MvcApplication1.Models;
 
namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/
        public ActionResult Index()
        {
            return View(new User());
        }
    }
}



Creating the configuring the view
1. Right click the Index method in the controller and add the view.
2. Make this strongly typed, or we will have a problem with the dynamic operations we will be using in the view (Example error: CS1963: An expression tree may not contain a dynamic operation)
3. Enter the following form information into the view...

@using MvcApplication1.Models
@model User
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
<h2>Sample EMF Class Validation</h2>
 
@using (Html.BeginForm())
{
    <fieldset>
    <p>
        @Html.LabelFor(Model => Model.Name)
        @Html.TextBoxFor(Model => Model.Name)
        @Html.ValidationMessageFor(Model => Model.Name)
    </p>
    <p>
        @Html.LabelFor(Model => Model.Email)
        @Html.TextBoxFor(Model => Model.Email)
        @Html.ValidationMessageFor(Model => Model.Email)
    </p>
    <p>
        <input type="submit" value="Submit" />
    </p>
    </fieldset>
}


We are almost there, but one more thing!! We need to add a reference to the jquery validation libraries. You can either do this in your view (using sections from the main layout page) or simply add the following into the head on the _Layout.cshtml page...

    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>



Download Sample Files Here


Enjoy!

No comments: