This blog post is based on an excellent video by Brad Wilson delivered at this year’s NDC. It’s a walk-through of how to quickly build a real time web application, in this case a To Do List application, using Knockout, Web API, and SignalR.
You can find the example code on GitHub – https://github.com/bradwilson/ndc2012.
This video covers using the following technologies to build a truly awesome application quickly:
- Knockout – http://knockoutjs.com/
- Web API – http://www.asp.net/web-api
- SignalR – http://signalr.net/
The idea here is that there is a clear separation between the client and the server. The client runs as an MVVM application written in javascript. Specifically written in Knockout in this case.
Then, to provide communication between the client and the server there are two options, Web API and SignalR.
Web API provides the ability to build a RESTful interface for the client to communicate with. SignalR provides a full duplex connection, over websockets, or emulates one using graceful degradation.
In the video Brad talks about using Web API to make changes to the application state and then pushing those changes out to any clients concerned with the change. This uses the full duplex communication that SignalR provides.
Looking at the code it can be seen how this is accomplished. By making the Hubs from SignalR available to the Web API Controller the response can be pushed out over the Hub to all of the Clients –
public class ToDoController : ApiControllerWithHub<ToDoHub>
{
private static List<ToDoItem> db = new List<ToDoItem>
{
new ToDoItem { ID = 0, Title = "Do a silly demo on-stage at NDC" },
new ToDoItem { ID = 1, Title = "Wash the car" },
new ToDoItem { ID = 2, Title = "Get a haircut", Finished = true }
};
private static int lastId = db.Max(tdi => tdi.ID);
…
public HttpResponseMessage PostNewToDoItem(ToDoItem item)
{
lock (db)
{
// Add item to the "database"
item.ID = Interlocked.Increment(ref lastId);
db.Add(item);
// Notify the connected clients
Hub.Clients.addItem(item);
// Return the new item, inside a 201 response
var response = Request.CreateResponse(HttpStatusCode.Created, item);
string link = Url.Link("apiRoute", new { controller = "todo", id = item.ID });
response.Headers.Location = new Uri(link);
return response;
}
}
…
}
From the Client it can be seen that the Knockout observable then receives the update from the SignalR Client rather than from the response to the RESTful call –
self.sendCreate = function () {
$.ajax({
url: "/api/todo",
data: { 'Title': self.addItemTitle(), 'Finished': false },
type: "POST"
});
self.addItemTitle("");
};
…
hub.addItem = function (item) {
viewModel.add(item.ID, item.Title, item.Finished);
};
Notice how easy it is to get a real time application communicating changes to a number of Clients. One final thing to consider is how easy it is to update the view in the client with the data coming back over this connection –
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>NDC Demo</title>
<link rel="shortcut icon" href="favicon.ico" />
<link rel="stylesheet" type="text/css" href="css/site.css" />
</head>
<body>
<form data-bind="submit: sendCreate">
<label for="title">Add a task:</label>
<input type="text" name="title" id="title" data-bind="value: addItemTitle, valueUpdate: 'afterkeydown'" />
<input type="submit" title="Add a new item" value="Add" disabled="disabled" data-bind="enable: addItemTitle().length > 0" />
</form>
<section data-bind="visible: items().length > 0" style="display: none">
<h1>Items in Progress</h1>
<table data-bind="foreach: items">
<tr>
<td>
<input type="checkbox" data-bind="checked: finished" />
<span data-bind="text: title, css: { finished: finished }"></span>
</td>
<td><input type="button" value="Delete" data-bind="click: remove" /></td>
</tr>
</table>
</section>
</body>
<script type="text/javascript" src="js/jquery-1.7.2.js"></script>
<script type="text/javascript" src="js/knockout-2.1.0.js"></script>
<script type="text/javascript" src="js/jquery.signalR-0.5.0.js"></script>
<script type="text/javascript" src="signalr/hubs"></script>
<script type="text/javascript" src="js/todo.js"></script>
</html>
With a minimal amount of HTML and declarative markup for the data binding it’s very easy to integrate the data from the application with the view that the user is interacting with.
And so, using these three technologies modern, real time web applications can be built with a minimal amount of effort.
Awesome link, JB. I’m going to play around with SignalR right now. I was unaware of that technology.
As for Web API, I know we used that along side MVC Controllers on WannaDo, but I’m not really clear on the tipping point for when you should implement API controllers in addition to or in place of MVC Controller action methods. Are there any reasons other than exposing your API data in additional formats (XML, etc.) or to third parties?