Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.
gregmac edited this page Feb 24, 2012 · 4 revisions

Todomvc How-To

In this example, I'll walk through the process of creating a Todomvc app using NServiceMVC. I'm going to use the Backbone Todomvc example by Jérôme Gravel-Niquet as the basis.

Create project

First step is to create a new MVC3 project, I'll call it "NServiceMVC.Examples.Todomvc"

New Project

I'm going to just use an "Empty" application

Empty MVC3 app

Install backbone.js

Because I'm using backbone for this, I'm going to install the Backbone nuget package.

Install backbone with nuget

Import the Backbone Todomvc example

I'm using the code at http://documentcloud.github.com/backbone/examples/todos/index.html. I will import index.html (as default.htm, to appease IIS), todo.js, backbone-localstorage.js, and todo.css. All I have to do is modify default.htm to have the correct path references.

Update default.htm references

One last thing, I'll add routes.IgnoreRoute(""); to my Global.asax.cs file so that my default.htm page will get loaded by default.

Add IgnoreRoute

At this point, I can hit F5, and I get the existing Todomvc demo working with its localstorage adapter

Todomvc working with localstorage

Install NServiceMVC

Now, I'm going to install NServiceMVC using nuget

Install nservicemvc with nuget

Just to check that it's working, I'm going to run the project again (F5) and then manually navigate to /metadata, the default location NServiceMVC serves its metadata page at. I get a page showing me I have no routes and no models, but this does confirm that NServiceMVC was installed correctly.

NServiceMVC empty metadata page

Change the Todomvc app to use remote storage

In todos.js, there is a line that sets up localstorage:

        // Save all of the todo items under the `"todos"` namespace.
        localStorage: new Store("todos"),

I'm going to remove that, and replace it with:

        // Use a base url of /todos
        url: 'todos',

This instructs backbone to use /todos as the basis for all its REST calls.

Now when I reload todomvc and watch the Network tab in the dev console, I can see it request /todos and get a 404, which I'd expect since I haven't written any service methods yet.

404 on Load

Create Todo Model

Before I can create the service, I have to create a model for the data I'll be returning -- in this case, Todo items. This is just a normal Data Transfer Object (DTO) -- or in other words, a plain C# class. I'll create it in the Models directory.

namespace NServiceMVC.Examples.Todomvc.Models
{
    public class Todo
    {
        public Todo()
        {
            Id = Guid.NewGuid();
        }

        public Guid Id { get; set; }
        public string Text { get; set; }
        public bool Done { get; set; }
        public int Order { get; set; }
    }
}

Create the GET /todos service

Next up, I am going to create the basic service to handle returning the list of Todos. To keep it simple to start with, I'm just going to return a hardcoded list of items.

using System.Collections.Generic;
using NServiceMVC;
using AttributeRouting;

namespace NServiceMVC.Examples.Todomvc.Controllers
{
    public class TodosController : ServiceController
    {
        [GET("todos")]
        public IEnumerable<Models.Todo> Index()
        {
            return new List<Models.Todo>() {
                new Models.Todo() {
                    Text = "Item1",
                },
                new Models.Todo() {
                    Text = "Item2",
                    Done = true,
                }
            };
        }
    }
}

A few things to note here:

  • The controller extends NServiceMVC.ServiceController instead of System.Web.Mvc.Controller.
  • My method returns a .NET type: IEnumerable<Models.Todo> instead of ActionResult.
  • I decorate the method with [GET("todos")] (which is part of AttributeRouting) which controls where and how this resource is served, in this case by calling GET /todos

Now we hit F5, and.. what the heck? Two empty items?

Empty items in todomvc

To check out what's going on, we can navigate manually to the /todos page to see what we get.

Manually navigate to /todos

As you can see, NServiceMVC formats this into an HTML page automatically. The result is an Array of Todo items (note that NServiceMVC returns any kind of enumerable/list/array as an array primitive), and we do in fact see "Item1" and "Item2" listed there. We can also see this resource as JSON, by either clicking on the JSON button or appending ?format=json to the URL.

JSON format

The problem we have here is that our service is returning PascalCase while the Todomvc javascript app is expecting camelCase.

Configure NServiceMVC to return camelCase JSON

Luckily, there's an easy fix for this, which is to modify the NServiceMVC configuration and turn on JSON Camel case option.

In the App_Start folder, there is a file called NServiceMVC.cs, open that, and add config.JsonCamelCase = true; to the config method.

Add JsonCamelCase=true

Now if we reload /todos?format=json we get the results in camelCase:

GET /todos with camelCase option on

When we refresh the Todomvc app, we now get the hardcoded items from NServiceMVC! Success!

Todomvc with hardcoded items returned from NServiceMVC

Create other REST methods

Up to this point, the Todomvc is not really functional, since nothing else is wired up. I'm going to build up the rest (rimshot) of the basic methods, and just use an in-memory list to store everything.

    public class TodosController : ServiceController
    {
        private static IList<Models.Todo> Todos; // in-memory static list. Note no thread-safety!
        public TodosController()
        {
            if (Todos == null) 
                Todos = new List<Models.Todo>(); // initialize the list if it's not already
        }

        [GET("todos")]
        [Description("List all Todos")]
        public IEnumerable<Models.Todo> Index()
        {
            return Todos;
        }

        [POST("todos")]
        [Description("Add a Todo")]
        public Models.Todo Add(Models.Todo item)
        {
            Todos.Add(item);
            return item;
        }

        [PUT("todos/{id}")]
        [Description("Update an existing Todo")]
        public object Update(Guid id, Models.Todo item)
        {
            var existing = (from t in Todos where t.Id == id select t).FirstOrDefault();
            if (existing != null)
                existing = item;
            return null;
        }

        [DELETE("todos/{id}")]
        [Description("Delete a Todo")]
        public object Delete(Guid id)
        {
            var existing = (from t in Todos where t.Id == id select t).FirstOrDefault();
            Todos.Remove(existing);
            return null;
        }
    }

Keep in mind I'm just trying to demonstrate the REST functionality here. I would normally not include this type of logic in the controller methods, but I'll refactor that part out later -- it's not important for this demo.

Now if I fire up the Todomvc app once again, I get a blank list (and I can see a GET request). If I add a couple items, I can see the POST requests.

Wired up, two new items

I'm just going to examine the POST request:

New item POST request

Note that backbone didn't send an id property over. That's getting generated server-side: in my Todo model's constructor, I have: Id = Guid.NewGuid();, and so when my controller method returns the item, it is returned with a new Id, which we can see in the POST response:

new item POST response

When I click an item to mark it as complete, I can see Backbone make a PUT request to update the item:

PUT request to mark complete

At this point, really, this is a functional Todomvc application backed by an NServiceMVC-based REST service.

NServiceMVC Metadata

If you remember, one of the first pages I loaded up was /metadata, which was blank at the time. Now that I have some resources defined, I'll load that page up again.

Metadata page for basic RESt methods

As you can see, it's found our four methods, as well as the Todo model. If you notice in my controller code, I also added a [Description] attribute (System.ComponentModel.Description) which NServiceMVC has picked up.

I can click on "GET todos" and see more information about that method:

Metadata details for GET /todo

I can also see examples of the model, which have sample data auto-generated depending on the type:

Metadata details for Todo model

Metadata XML sample for Todo model

Metadata C# sample for Todo model

Another really handy feature is the ability to do basic operations from within the metadata page, like creating a new item. Note that by default a sample object is provided, but I've removed the id and order properties because I don't care about them now.

Manual POST operation from metadata page

Next Steps

You can check out the full code for this demo (or use Git to download and run it yourself). Check the commit history to see all the steps individually as it's being built.

You should also read the main NServiceMVC documentation or visit http://nservicemvc.com.

There is also a HowtoPart2 that covers a few more things.