Spa is quite hot right now. There are many client choices. The reason why I chose backbone.js is because it supports connecting to a json web api. I am building an app on top of ASP.NET web api so I want to see how easy to make them work together.

I won't talk about too much about how backbone.js works. You can got to http://backbonejs.org for it's documentation and I findhttp://backbonetutorials.com is quite helpful to learn it.

You can download the sample here

Backbone.js Todo List Sample

To make things easy. I directly copy the sample code from backbone.js source.

The sample is quite simple. It implements a todo list and save the data in browser local storage.

Let's first take a look of backbone.js model

 1: // Our basic **Todo** model has `title`, `order`, and `done` attributes. 
 2: var Todo = Backbone.Model.extend({ 
 3:     // Default attributes for the todo item. 
 4:     defaults: function() { 
 5:         return { 
 6:             title: "empty todo...", 
 7:             order: Todos.nextOrder(), 
 8:             done: false }; 
 9:     }, 
 10: ... 

The model has three attributes: title, order and done. Each maps model property in C# world.

Backbone.js has a collection concept that represents a collection of model.

 1: // The collection of todos is backed by *localStorage* instead of a remote 
 2: // server. 
 3: var TodoList = Backbone.Collection.extend({ 
 4:     // Reference to this collection's model. 
 5:     model: Todo, 
 6:  
 7:     // Save all of the todo items under the `"todos"` namespace. 
 8:     localStorage: new Store("todos-backbone"), 
 9:  
 10: ... 

The collection defines its model as Todo and assign a local storage which will save the data to browser's storage. As we are going to use web api,

Create server model and web api

Based on the model on in the backbone.js sample, I create a corresponding EF code first mode.

 1: public class Todo 
 2: { 
 3:     public int Id { get; set; } 
 4:     public string Title { get; set; } 
 5:     public int Order { get; set; } 
 6:     public bool Done { get; set; } 
 7: } 

And create a EF scaffolding API controller based on the model. Simple? Yeah, it's done for the server side.

Connect client to the server

I just changed the localStorage line to the url to tell backbone to use a web api instead of browser storage.

 1: // The collection of todos is backed by *localStorage* instead of a remote 
 2: // server. 
 3: var TodoList = Backbone.Collection.extend({ 
 4:     // Reference to this collection's model. 
 5:     model: Todo, 
 6:     url: function () { return 'api/todos'; },
 7: ... 

You many notice that there is something different between server and client code: Model's property names are different by their first letter cases.

Web API uses JSON.NET to serialize and deserialize json. Fortunately, JSON.NET supports case insensitive deserialization by default. And it can support serialization as well by adding one line code in WebApiConfig.cs.

 1: public static void Register(HttpConfiguration config) 
 2: { 
 3:     config.Formatters.JsonFormatter.SerializerSettings.ContractResolver 
 4:         = new CamelCasePropertyNamesContractResolver(); 
 5:     config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); 
 6: } 

The CamelCasePropertyNamesContractResolver will automatically convert property name to camel case, which is same as the attribute name on client side.

After this change, every thing works like a charm.

Conclusion

To implement a SPA with backbone.js and ASP.NET web api is quite easy. It's because they are all based on Restful convention. Backbone.js enforce a best practice to organize client code which looks very useful when the application grows. It also supports hashtag routing. I will give it a try in a more complicated application.

You can download the sample here