-
Notifications
You must be signed in to change notification settings - Fork 0
Howto
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.
First step is to create a new MVC3 project, I'll call it "NServiceMVC.Examples.Todomvc"
I'm going to just use an "Empty" application
Because I'm using backbone for this, I'm going to install the Backbone nuget package.
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.
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.
At this point, I can hit F5, and I get the existing Todomvc demo working with its localstorage adapter
Now, I'm going to install NServiceMVC using 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.
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.
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; }
}
}
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 ofSystem.Web.Mvc.Controller
. - My method returns a .NET type:
IEnumerable<Models.Todo>
instead ofActionResult
. - 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 callingGET /todos
Now we hit F5, and.. what the heck? Two empty items?
To check out what's going on, we can navigate manually to the /todos page to see what we get.
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.
The problem we have here is that our service is returning PascalCase while the Todomvc javascript app is expecting camelCase.
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.
Now if we reload /todos?format=json
we get the results in camelCase:
When we refresh the Todomvc app, we now get the hardcoded items from NServiceMVC! Success!
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.
I'm just going to examine the 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:
When I click an item to mark it as complete, I can see Backbone make a PUT request to update the item:
At this point, really, this is a functional Todomvc application backed by an NServiceMVC-based REST service.
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.
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:
I can also see examples of the model, which have sample data auto-generated depending on the type:
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.
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.