ASP.NET MVC 3: Ajax Form with jQuery validate supporting (unobtrusive) Client Side Validation and Server Side Validation

Update 2011-08-07: I’ve written a new follow-up blog post to this one which shows how to upgrade the techniques described here with custom (jQuery) JavaScript code to implement a more flexible Ajax form handling.

This blog post shows step by step instructions how to build an Ajax form with jQuery validate supporting (unobtrusive) client and server side validation using ASP.NET MVC 3.

Summarized the (Ajax) form will have the following features:

  1. Client side validation: Before submitting the data to the server the client validates the data to reduces the number of requests and to improve usability.
  2. Server side validation: The server validates the data again to find malicious requests that bypasses client side validation and to perform additional validations that cannot be done on client side, e.g. validations that need database access.
  3. Partial page updates: If server side validation fails the error messages are injected in the DOM on the client side to avoid complete page reloads.

To follow the steps below you can start from a new (empty) ASP.NET MVC 3 Web Application with Razor support or you can download the Visual Studio 2010 project containing all the source code here.

To enable (unobtrusive) client side Ajax and validation support include the following JavaScript files (in Views/Shared/_Layout.cshtml):

and make sure, that ClientValidationEnabled and UnobtrusiveJavaScriptEnabled is enabled in your Web.config (which should be the default values):


Next, we create a Model (Models/ValidationModel.cs) which defines a property with some validation attributes:

public class ValidUserNameAttribue : ValidationAttribute
  public override bool IsValid(object value)
    return (value != null && value.ToString() == "Bob");

public class ValidationModel
  [StringLength(8, MinimumLength = 3)]
  [ValidUserNameAttribue(ErrorMessage = "User name != 'Bob'")]
  [Display(Name = "User Name")]
  public string UserName { get; set; }

The custom ValidUserNameAttribue adds a validation that is only performed on server side. In a real world example this attribute could for example query a database to ensure the user name is unique. In this example only “Bob” is accepted as a valid user name. Both other attributes (Required and StringLength) trigger validation on client and on server side.

The (minimalistic) HomeController defines two actions: Index to render the form and Form to validate the request and render the result.

public class HomeController : Controller
  public ActionResult Index()
    return View(new ValidationModel());

  public ActionResult Form(ValidationModel validationModel)
    return PartialView(!ModelState.IsValid ? "Partial/_Form" : "Partial/_Success", validationModel);

In a last step we need to define the views. As you can see in the HomeController‘s Form action we will use partial views for the form and the success message to enable the partial page updates on the client side.


@model MVC3_Ajax_Form_jQuery_Validation.Models.ValidationModel

    ViewBag.Title = "ASP.NET MVC 3: Ajax Form with jQuery validate supporting Unobtrusive Client Validation and Server Side Validation";

@DateTime.Now: Index.cshtml rendered


The Index view defines a <div> tag that is used as form container, i.e. it’s content is replaced with the server’s response. If the server side validation fails the server sends HTML code of the form containing server side validation error messages, otherwise HTML code containing a success message.


@model MVC3_Ajax_Form_jQuery_Validation.Models.ValidationModel

@DateTime.Now: Partial/_Form.cshtml rendered

@using (Ajax.BeginForm("Form", new AjaxOptions() { UpdateTargetId = "FormContainer" , OnSuccess = "$.validator.unobtrusive.parse('form');" })) {

Error Message: @Html.ValidationMessageFor(m => m.UserName)

@Html.LabelFor(m => m.UserName): @Html.EditorFor(m => m.UserName)


The Partial/_Form.cshtml partial view defines the (Ajax) form. This partial view is included with @Html.Partial()in the Index view for the initial page load and used by the HomeController‘s Form action to render the form with server side validation messages.
It’s important to call $.validator.unobtrusive.parse(‘form’); in the OnSuccess callback to reinitialize the client side validation after the form container’s HTML content is replaced!


@model MVC3_Ajax_Form_jQuery_Validation.Models.ValidationModel

User name '@Model.UserName' is valid :)

The Partial/_Success.cshtml partial view defines the success message that is used to replace the form after the request passes server side validation.

Both the view Home/Index.cshtml and Home/Partial/_Form.cshtml render the current time-stamp that shows that the partial page update is working: After submitting a user name unequals ‘Bob’ only form render time-stamp changes.

You can download the Visual Studio 2010 project containing all the source code here.


17 responses to “ASP.NET MVC 3: Ajax Form with jQuery validate supporting (unobtrusive) Client Side Validation and Server Side Validation”

  1. Thanks for that, ,first example on the web that I have founf that actually works. Much love.

  2. I doubt in the following three mvc ajax (, jquery and Partial Views).

    I want to update a table (add, delete, update and save), using ajax.

    Adapted the tutorial up there for my needs.

    Clicking a button (eg, add table) works on some tables more in the other if the following error:

    The script on this page May Be Busy, or It May have stopped responding. Can you stop the script now, or you can proceed to see if the script will complete.

    Script: http://localhost:4951/Scripts/Wijmo-Open/development-bundle/external/jquery-1.5.2.min.js:16

  3. clear, concise, easy to follow.
    downloaded sample code, unzipped, compiled and ran — stepped through with debugger to fully grasp — everything worked perfectly.

    This post has finally solved my numerous stabs at the issue


  4. I’m building an application using jQuery UI tabs and form validation using AJAX. I wish to achieve the user authentication, then have it show the other tabs of the application upon authentication success. But then, I finally found your post with form validation which is actually what was missing to get the gist of it.

    Thanks for this useful post, I love it! And be sure I’ll follow the other related articles too so that I can fully grasp the different aspects presented.

    Thanks again! =)

  5. I am new to MVC3 + Razor + jQuery + Ajax.
    I have a viewModel that my View is based on and am trying to do an ajax callback to my Controller when user clicks on a button (ie. clear grid rows).
    Manage to get Controller method being called (after removing the httppost attribute from method).
    public ActionResult ClearAllRows(ManageJobsViewModel model)
    Problem is that values in my model are null, except for one had changed.
    But the grid is strictly display only, so its rows do not change and so it seems I get back a null for my viewmodel collection property.

    How can I force the data being sent from ajax to be a fully populated viewModel?

  6. Hi Sheir,
    If you would like to use the approach presented in the blog post for a grid view, I would suggest to create a partial view that renders the grid view (like Home/Partial/_Form.cshtml for the form in the example) and your ClearAllRows() action should return this partial view. On the client side you need to update the grid by replacing the grid’s DOM node with the DOM of the rendered partial view that is returned from the server.
    I would recommend to take a look at part 2 and part 3 of my blog posts to get an idea about implementing AJAX in ASP.NET MVC. Please keep in mind that the blog posts are focused on validation and handling form data and the approach could not be used one-to-one for grid views.
    Hope this helps …

  7. Thanks.
    Now my form has multiple submit buttons and I have used a special custom attribute I found via some article I found on google search.
    So normal non-ajax way works nicely..postback..entire page refresh/reload.

    Now I have been trying all weekend to ajax-ify the buttons and NO luck.
    I am extremely tired now and mad frustrated.

    As an example, take the ClearAllRows, I have a function in my home controller and it has the attribute that maps the html form post method (aka managejob) to it from that submit button. In normal postback, it all works.

    When I tried ajax the button, with url of home/clearallrows; it blows up and I cannot figure it out. Like I had mention, I am new to this world.

    Very tired and frustrated. Can you hellp with the ajax-ify of my multiple submit buttons?

  8. Sorry forgot to get back to you. Manage to solve the issue — ajaxify of my form with the multiple submit buttons.
    What I had to do was create a method in my controller (tagged with HttpPost attribute) and this method would then just call my normal postback functions.

    As an example: This is my normal postback Controller method for the ClearAll.

    [SubmitActionName(ActionName=”ManageJob”, SubmitButton = “btClearAllRows”)]
    public ActionResult ClearAllRows(MyViewModel e)
    //do stuff
    {//more stuff
    return Json(someObject, JsonRequestBehavior.AllowGet);
    return RedirectToAction(“Index”);

    public ActionResult AjaxClearAllRows(MyViewModel e)
    return ClearAllRows(e);

    In my view, I had code such as:
    $(“#btClearAllRows).on(“click”, function (event) {
    var formToSubmit = $(‘form:first’);
    var param = $(formToSubmit).serialize();
    var lnk = ‘@Url.Action(“AjaxClearAllRows”, “Home”);

    url: lnk,
    type: “POST”,
    dataType: “json”,
    context: document.body,
    data: param,
    cache: false,
    success: AjacClearAllSuccess,
    error: AjaxError,
    complete: AjaxComplete

    So in my AjacClearAllSuccess I would just replace a div with the data I got from the controller method (ie a partial view rendered to string and passed as json). Example:
    function AjacClearAllSuccess (data, textStatus, jqxHR) {

    It works nicely.

  9. Many thanks for this article, I was pulling my hair out trying to get this to work, the missing secret was:


    Thanks again

Leave a Reply

Your email address will not be published. Required fields are marked *