Category Archives: ASP.NET

Using Web API Validation with jQuery Validate

Building on my last post about validating your model with Web API, if you’re calling a Web API controller from JavaScript you may need to parse the validation result and display it on the screen.

Most people using MVC would be using the jQuery Validate plugin that’s been included with the default template for quite a while now. While most validations are performed using JavaScript adapters, some are only performed server side. As a result, the regular unobtrusive JavaScript adapters will not catch this before the post occurs. This means that you if you are using JavaScript requests with Web API to handle data manipulation you will need to somehow manually handle the validation errors that will be returned.

Plugging into jQuery Validation is actually quite easy… To validate a form, simply select the form using jQuery and call .validate() on it – e.g.

var validator = $('.main-content form').validate();

This will return a validator object will a few handy methods on it. Two of which are valid() and showErrors(). The valid method will return a Boolean value indicating whether the form is valid or not and the showErrors method will show any validation errors on the current form. The showErrors method also accepts an object that defines any additional error messages you wish to display – e.g. to display the message “The title is incorrect” for a property named Title:

validator.showErrors({ Title: 'The title is incorrect.' });

Now, assuming I a view with the following mark-up inside the form, I should see a validation error:

<div class="editor-label">@Html.LabelFor(model => model.Title)</div>
<div class="editor-field">
    @Html.TextBoxFor(model => model.Title)
    @Html.ValidationMessageFor(model => model.Title)
</div>


But how do we connect this to Web API…? Well, if you’ve read my previous post you’ll recall that calling a Web API controller’s PUT action that’s decorated with the ValidateFilter attribute I created will return a collection of validation errors if the model is not valid. To test this, I’ll modify my TodoApiController from the previous post as follows:

[ValidateFilter]
public void Put(int id, TodoItem value)
{
    if (value.Title == "hi there")
        ModelState.AddModelError("Title", "The title is incorrect.");

    if (!ModelState.IsValid) return;

    db.Entry(value).State = EntityState.Modified;
    db.SaveChanges();
}

I should now receive a validation error whenever I try to update an item with the title “hi there”. Let’s write some jQuery to submit my form:

function updateItem(form, url) {
    var validator = form.validate(),
        serialized = form.serializeArray()
        data = { };

    if (!validator.valid()) { return; }

    // turn the array of form properties into a regular JavaScript object
    for (var i = 0; i < serialized.length; i++) {
        data[serialized[i].name] = serialized[i].value;
    }

    $.ajax({
        type: 'PUT', // Update Action
        url: url, // API Url e.g. http://localhost:9999/api/TodoApi/1
        data: data, // e.g. { TodoItemId: 1, Title: 'hi there', IsDone: false }
        dataType: 'JSON',
        success: function () { alert('success'); },
        error: function (jqXhr) { extractErrors(jqXhr, validator); }
    });

}

Now let’s look at extractErrors:

function extractErrors(jqXhr, validator) {

    var data = JSON.parse(jqXhr.responseText), // parse the response into a JavaScript object
        errors = { };

    for (var i = 0; i < data.length; i++) { // add each error to the errors object
        errors[data[i].key] = data[i].value;
    }

    validator.showErrors(errors); // show the errors using the validator object
}

Lastly, attaching to the form’s submit event will call this whenever the Enter key is hit or the Submit button is clicked:

$('.main-content form').submit(function () {
    updateItem($(this), '/api/TodoApi/' + $('#TodoItemId').val());
});

Validating your model with Web API

One of the great things about ASP.NET 4.5′s Web API is that it’s built on the same (or similar) principles as MVC. This means that you get a lot of cool things out of your API controllers from MVC – like Action Filters.

While building my first Web API controller, I wanted to ensure that a creation or an update of an item was only done if that item was valid. I also wanted to pass any validation errors back to the client. This looks quite difficult at first because the Put and Post functions on an ApiController can’t return a result. Action Filters to the rescue!

With a simple action filter attribute, you can ensure that your models are validated and the errors are returned in a simple format to the client by decorating the appropriate methods.

Note: Code also available on Gist - https://gist.github.com/1920999

public class ValidateFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var modelState = actionExecutedContext.ActionContext.ModelState;
        if (!modelState.IsValid)
        {
            var errors = modelState
                .Where(s => s.Value.Errors.Count > 0)
                .Select(s => new KeyValuePair<string, string>(s.Key, s.Value.Errors.First().ErrorMessage))
                .ToArray();

            actionExecutedContext.Result = new HttpResponseMessage<KeyValuePair<string, string>[]>(
                errors,
                HttpStatusCode.BadRequest
            );
        }
    base.OnActionExecuted(actionExecutedContext);
}

Now, for the controller implementation…

public class TodoApiController : ApiController
{
    private BetterMobileSpaContext db = new BetterMobileSpaContext();

    // GET /api/todoapi
    public IEnumerable<TodoItem> Get()
    {
        return db.TodoItems.ToList();
    }

    // GET /api/todoapi/5
    public TodoItem Get(int id)
    {
        return db.TodoItems.Find(id);
    }

    // POST /api/todoapi
    [ValidateFilter]
    public void Post(TodoItem value)
    {
        if (!ModelState.IsValid) return;

        db.TodoItems.Add(value);
        db.SaveChanges();
    }

    // PUT /api/todoapi/5
    [ValidateFilter]
    public void Put(int id, TodoItem value)
    {
        if (!ModelState.IsValid) return;

        db.Entry(value).State = EntityState.Modified;
        db.SaveChanges();
    }

    // DELETE /api/todoapi/5
    public void Delete(int id)
    {
        TodoItem todoitem = db.TodoItems.Find(id);
        db.TodoItems.Remove(todoitem);
        db.SaveChanges();
    }

    protected override void Dispose(bool disposing)
    {
        db.Dispose();
        base.Dispose(disposing);
    }
}

Now a Create (PUT) and an Update (POST) request will validate the model before invoking the appropriate action. Calling Create from using a JSON request with an invalid model would look something like this:

Request

Method: PUT

Body: { Title: ”, IsDone: false }

Response

Status Code: 400 (Bad Request)

Body: [{ "key": "Title", "value": "The Title field is required" }]

Using a valid model will simply result in a 200 (OK) response with no body.

NOTE: while writing this post I stumbled on these two blog posts that did the same thing and adapted my code:

EDIT 2012-02-27: Updated code to replace ValidationError type with KeyValuePair and changed filter to be after action execution so controller can perform any extra validation.

Making MVC 3 a little more… dynamic

The other day I ran into a little problem. I wanted to be able to post some JSON to a web service and have it accept a whole bunch of data (not exactly the technical term) that was not predefined.

Given this very vague problem, I decided I wanted to use ASP .NET MVC 3. So starting with File\New Project, I added a method to my HomeController as follows:

[HttpPost]
public ActionResult DoSomething(string a, string b, dynamic c)
{
    return new EmptyResult();
}

The thought behind this was that I wanted to supply two required properties (a and b) and basically have a dynamic bag for everything else. Also, I didn’t want to be restricted to a single layer of properties. Instead, I wanted to be able to pass a deep tree and have it totally accessible.

Then I pulled up fiddler and set up a request with the following details:

Method POST
URL http://localhost:2643/Home/DoSomething
Request Headers User-Agent: Fiddler

Content-Type: application/json

Request Body { a: “Hello”, b: “World”, c: { d: “this”, e: “is”, f: “dynamic” } }

image

When I hit execute and set a breakpoint on the action, I received the following values in my locals:

clip_image002

As expected, the JsonValueProviderFactory has kicked in and populated the values of a and b using the JSON provided. However, it cannot match c properly so simply throws an object at it that is not dynamic and does not have values on it, hence useless.

After some searching, I found a few valid solutions. The most useful one was this blog post by Anoop Madhusundanan. In this post, he describe the process of using a model binder and a custom model binder attribute to identify parameters of an action method that are to use the model binder. This seemed like a great solution for me, but had a couple of little problems… Most importantly, Anoop’s solution does not allow for multiple parameters on an action method or mapping the parameter to the property in the JSON object.

I came up with a very similar way of solving this problem. I created a class named DynamicJsonBinder which implements IModelBinder, just like Anoop. The main difference with my solution is that I provided a way to ensure that the parameter being populated with the dynamic object is mapped based on the name of the parameter. This is done by using a switch on the attribute called MatchName, which will cause the binder to look at the parameter name and find the matching property in the JSON object to return.

Here’s the attribute:

using System.Web.Mvc;

public class DynamicJsonAttribute : CustomModelBinderAttribute
{
    public override IModelBinder GetBinder()
    {
        return new DynamicJsonBinder(MatchName);
    }

    public bool MatchName { get; set; }
}

And here’s the model binder:

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Web.Helpers;
using System.Web.Mvc;

public class DynamicJsonBinder : IModelBinder
{
    private readonly bool matchName;

    public DynamicJsonBinder(bool matchName)
    {
        this.matchName = matchName;
    }

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var contentType = controllerContext.HttpContext.Request.ContentType;
        if (!contentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            return null;

        string bodyText;
        using (var stream = controllerContext.HttpContext.Request.InputStream)
        {
            stream.Seek(0, SeekOrigin.Begin);
            using (var reader = new StreamReader(stream))
                bodyText = reader.ReadToEnd();
        }

        if (string.IsNullOrEmpty(bodyText)) return null;

        var desiralized = Json.Decode(bodyText);

        if (!matchName) return desiralized;

        var members = desiralized.GetDynamicMemberNames() as IEnumerable&lt;string&gt;;
        return members == null
            || members.Contains(bindingContext.ModelName)
            ? desiralized[bindingContext.ModelName] : null;
    }
}

So if by adding a DynamicJson attribute to the c parameter on the action method, we’ll get the following:

public ActionResult DoSomething(string a, string b, [DynamicJson] dynamic c)
{
    return new EmptyResult();
}

Debugging into this with the same post request as earlier:

clip_image004

We see that c has been populated with a DynamicJsonObject (the result of the call to Json.Decode) and that it has recursively mapped the properties under the JSON object to dynamic object. However, the value is the entire JSON object, that is it’s not mapped to the c property.

To enable name matching we get the following code:

[HttpPost]
public ActionResult DoSomething(string a, string b, [DynamicJson(MatchName = true)] dynamic c)
{
    return new EmptyResult();
}

Debugging we get:

clip_image006

And we see that the property has been matched correctly and the correct value is passed through to the parameter.

Using these two simple classes and a bit of dynamic know-how, I’ve managed to post anything to my web service and have it dynamically accessible. This basically means we have the equivalent of a property bag on steroids that can be queried and manipulated in the same way as any dynamic object. We can even re-serialize the dynamic object to JSON and store it as is if required.

Want Open Search Integration in Your Website…?

Over the past few weeks, Tatham Oddie, Damian Edwards and myself have been working on publishing a framework/toolkit for integration OpenSearch into any ASP.NET search enabled website. I’m pleased to announce we have finally hit a release!

The project is available at opensearchtoolkit.codeplex.com. Tatham has a great post on how to integrate it into your site on his blog

OpenSearch is a technology that already has widespread support across the web and is now getting even more relevant with Internet Explorer 8’s Visual Search feature and the Federated Search feature in the upcoming Windows 7 release.

Now it’s time to make it even easier. Ducas Francis, one of the other members of my team, took on the job of building out our JSON feed for Firefox as well as our RSS feed for Windows 7 Federated Search. More formats, more fiddly serialization code. Following this, he started the OpenSearch Toolkit; an open source, drop-in toolkit for ASP.NET developers to use when they want to offer OpenSearch.

Today marks our first release.

So get on over to codeplex, hit up Tatham’s blog for instructions and drop the toolkit into your web site so you can take advantage of all the coolness that is OpenSearch.

Follow

Get every new post delivered to your Inbox.