Getting started with ASP.NET Web API part 2

This is the sequel from this post. Enter the micro ORM I happen to like micro ORM’s. I love plain SQL. I love minimalism. So that rules out the Entity Framework for me. My favorite is PetaPoco. I use it all the time. After the AddressBook database has been created, you will need to create a Person class that matches the Person table in the database:

[code lang=”csharp”]
public class Person
{
public int Person_Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string County { get; set; }
public string State { get; set; }
public string ZIP { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public string Email { get; set; }
public string Web { get; set; }
}
[/code]

And then open the Nuget package manager console and install PetaPoco:

[code lang=”powershell”]
Install-Package PetaPoco.Core
[/code]

And now the CRUD. Retrieving persons from the database Edit PersonController.cs to make a call to the database using PetaPoco:

[code lang=”csharp”]
using System.Net.Http;
using System.Web.Http;
using System.Collections;
using AddressBook.Api.Models;
using SqlFu;
using System.Net;

namespace AddressBook.Api
{
public class PersonController : ApiController
{
public PetaPoco.Database db =
new PetaPoco.Database("AddressBookConnectionString");

public IEnumerable Get()
{
var persons =
db.Query("SELECT * FROM PERSON ORDER BY LastName");
return persons;
}
}
}

[/code]

Next hit F5 and browse to http://localhost1234/Person or whatever port your webserver is running on.

That doesn’t work:

2013-07-22 23_10_43-localhost_54555_Person_

Its throwing an exception: “The ‘ObjectContent`1’ type failed to serialize the response body for content type ‘application/xml; charset=utf-8′” The solution is disabling the XML formatter completely and have it return JSON all the time. This is done in Global.asax in the Application_Start method. You should add the following lines:

[code lang=”csharp”]
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
[/code]

That makes the Application_Start method in Global.asax look like this:

[code lang=”csharp”]
protected void Application_Start(object sender, EventArgs e)
{
var config = GlobalConfiguration.Configuration;
config.Routes.MapHttpRoute(
name: "default",
routeTemplate: "{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
});

//disable XML formatting and return JSON all the time
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
}

[/code]

I honestly don’t know why I had to remove the XMLFormatter to make this work. I guess the POCO is not XML compatible or whatsoever. Some investigation is in order I suppose. However disabling XML works. After altering Global.asax everything works as expected.

. 2013-07-22 23_27_53-Fiddler Web Debugger

Adding a person to the database

Lets add a person to the database, using Fiddler. First, let’s create a POST method in PersonController.cs. It returns the URI for the new Person:

[code lang=”csharp”]
public HttpResponseMessage Post([FromBody] Person person)
{
db.Insert("Person", "Person_Id", person);
var response = Request.CreateResponse(HttpStatusCode.Created, person);

string uri = Url.Link("Default", new { id = person.Person_Id });
response.Headers.Location = new Uri(uri);
return response;
}
[/code]

In Fiddler:

2013-07-22 23_38_01-Fiddler Web Debugger

Click Execute.

. 2013-07-22 23_40_55-Fiddler Web Debugger T

The result is, as you can see, the header location that contains the Id for the inserted record. Hello Kitty is added to the database. The WebApi has consumed the input and PetaPoco has duly delivered it to the Persons table.

Getting a single person from the database

Now we now how this works, getting a single person is simple: Add this method:

[code lang=”csharp”]
public Person Get(int id)
{
var p = db.Single("SELECT * FROM PERSON WHERE Person_Id = @0", id);
return p;
}

[/code]

2013-07-27 23_03_23-Fiddler Web Debugger Click Execute: 2013-07-27 23_05_23-Fiddler Web Debugger

Updating a single person from the database

Add the following code to the PersonController:

[code lang=”csharp”]
public void Put([FromBody] Person person)
{
var p = db.Single("SELECT * FROM PERSON WHERE Person_Id = @0", person.Person_Id);
db.Update("Person", "Person_Id", person);
}
[/code]

Now choose PUT in fiddler and choose the Id you want edit: 2013-07-27 23_08_58-Fiddler Web Debugger Click Execute. The person will be updated.

Removing a person from the database

To remove a person add this method to the PersonController.cs:

[code lang=”csharp”]
public void Delete(int id)
{
var p = db.Single("SELECT * FROM PERSON WHERE Person_Id = @0", id);
db.Delete("Person", "Person_Id", p);
}
[/code]

To test it set Fiddler to DELETE: 2013-07-27 23_11_50-Fiddler Web Debugger There you go, we now have a very basic Web API. We do not have a client yet. Also, we just have one table/entity.

Not very exciting so far. I’m going to turn this up a nudge. Next time, I will migrate the database to MongoLab and start building a client with Angularjs.

Getting started with ASP.NET Web API part 1

Well, I am back. I have been working on a very large project the last couple of months that gently removed the spare time to blog about the things I care about. But I’m jumping in again.

What has happened since then?
Well, it is like the whole ecosystem has changed since last year. It’s all about mobile and BYOD. No one develops for the desktop anymore. Computer sales are dropping. Even Intel is now focussing on tablets and laptops because of declining revenues.

Of course we .NET developers still have a lots of work in enterprises so no worries there. But, if you start building an app, you’d better consider building it for mobile as well.

That means we need to write applications in a platform independent manner. So it means we have to decouple our apps. We need to provide an API that any client application (phone, tablet or desktop) can consume.

So, this is the moment to dive into the ASP.NET Web API which is very lightweight if you want it to.

What are we going to build?
We are going to create an addressbook. It’s a simple CRUD application.
This is What we need:
Visual Studio 2012.3
SQL 2012 Server Express

Next create a new database called AddressBook and execute this sql. Thanks to Brian Dunning.

Getting started with the Web API
Fire up Visual Studio and create a new empty Visual Studio Solution called AddressBook.
Add a new project to this solution -> Visual C# -> Web -> ASP.NET Empty Web Application called AddressBook.Api

In the Package Manager Console, type:

[code lang=”bash”]
Install-Package Microsoft.AspNet.WebApi
[/code]

Next add a new class and name it PersonController:
2013-07-19 10_37_56-AddressBook - Microsoft Visual Studio

Then make it look as follows:

[code lang=”csharp”]
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace AddressBook.Api
{
//class must inherit from the apiController
public class PersonController : ApiController
{
public IEnumerable Get()
{
return new string[] { "Marie", "Tina" };
}
}
}
[/code]

Now we must add a default route for the application. The routes are global to the application. So the place to configure the routes is in Global.asax. So go ahead and add a new Global Application Class file, and add the following:

[code lang=”csharp”]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Security;
using System.Web.SessionState;

namespace AddressBook.Api
{
public class Global : System.Web.HttpApplication
{

protected void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "default",
routeTemplate: "{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
});
}

[/code]

F5 and the result is like this:

2013-07-19 10_45_20-IIS 8.0 Detailed Error - 403.14 - Forbidden

Well that can’t be good.

According to our route, however, we must explicitly enter the name of our controller in the URL. And then it works:

2013-07-19 10_47_49-localhost_54555_Person

Next time I show how to display the data from the AddressBook database.