Hands-On Lab

Build RESTful APIs with WCF Web API

Lab version:1.1.0.0

Last updated:12/6/2011

Contents

Overview

Exercise 1: Create a Read-Only Service

Task 1 — Install NuGet Package Manager 1.5

Task 2 — Create the Visual Studio Solution

Task 3 — Define the Contact Resource

Task 4 — Create the Contact Repository

Task 5 — Create the Contact Service

Task 6 — Host the Service

Task 7 — Use the Browser to View the Contacts

Task 8 — Create a Client Application

Exercise 2: Create a Read/Write Service

Task 1 — Add a Method to Create New Contacts

Task 2 — Add a Method to Delete Contacts

Task 3 — Add a Method to Update Contacts

Task 3 — Update the Client

Exercise 3: Host the Service in ASP.NET (Optional)

Task 1 — Create an ASP.NET Web Project

Task 2 — Add the Contact Service Classes

Task 3 — Update the Service to Support Cache Control

Task 4 — Enable Routing

Task 5 — Use the Browser to View the Contacts

Task 6 — Add a JavaScript Client

Summary

Appendix: Using Code Snippets


Overview

In recent years, it has become clear that HTTP is not just for serving up HTML pages. It is also a powerful platform for building Web APIs, using a handful of verbs (GET, POST, and so forth) plus a few simple concepts such as URIs and headers.

WCF Web API is a set of Windows Communication Foundation (WCF) components that simplify HTTP programming. Because it is built on WCF, Web API automatically handles the low-level transport details of HTTP. At the same time, Web API naturally exposes the HTTP programming model. In fact, one goal of Web API is to not abstract away the reality of HTTP. As a result, Web API is both flexible and easy to extend.

In this hands-on lab, you will use the WCF Web API to build a simple REST API for a contact manager application. You will also build a client to consume the API. Prior knowledge of WCF is not necessary.

The REST architectural style has proven to be an effective way to leverage HTTP — although it is certainly not the only valid approach to HTTP. The contact manager will expose the following RESTful methods.

This lab requires a basic understanding of HTTP and REST.

Action / HTTP Method / Relative URL
Get a list of all contacts. / GET / /api/contacts
Get a contact by ID / GET / /api/contacts/id
Create a contact / POST / /api/contacts
Update a contact / PUT / /api/contacts/id
Delete a contact / DELETE / /api/contacts/id

Objectives

In this hands-on lab, you will learn how to:

  • Implement a RESTful Web API that supports GET, POST, PUT and DELETE verbs
  • Write an HTTP client that consumes the API
  • Work with HTTP headers and status codes
  • Host the API in an ASP.NET application

Prerequisites

  • Microsoft Visual Studio 11 Developer Preview
  • Windows PowerShell (for setup scripts – already installed on Windows 7 and Windows Server 2008 R2)

Setup

Throughout the lab document, you will be instructed to insert code blocks. For your convenience, most of that code is provided as Visual Studio Code Snippets, which you can use from within Visual Studio to avoid having to add it manually.

To install the code snippets:

  1. Open a Windows Explorer window and browse to the lab’sSource\Setupfolder.
  2. Double-click theSetup.cmd file in this folder to install the Visual Studio code snippets.

If you are not familiar with the Visual Studio Code Snippets, and want to learn how to use them, you can refer to the appendix from this document‘Using Code Snippets’.

Exercises

This hands-on lab includes the following exercises:

  1. Create a Read-Only Service
  2. Create a Read/Write Service
  3. Host the Service in ASP.NET

Estimated time to complete this lab: 60 minutes.

Exercise 1: Create a Read-Only Service

In this exercise, you will implement the read-only GET methods for the contact manager. You will also write a simple HTTP client to consume the service.

Task 1 — Install NuGet Package Manager 1.5

Execute this task if you do not have NuGet Package Manager installed in your Visual Studio environment.

  1. Run Visual Studio.
  2. From the Tools menu, select Extension Manager.
  3. In the Extension Manager wizard, select Online Extensions.
  4. In the search box, search for theNuGet Package Manager.

Figure 1

Installing NuGet Package Manager

  1. Click Download.
  2. Click Yes to install NuGet Package Manager.
  3. Restart Visual Studio.

Alternatively, you can download NuGet Package Manager fromthe MSDNVisual Studio Gallery (

Note: Make sure to install version 1.5, which is compatible with Visual Studio 11 Developer Preview.

Task 2 — Create the Visual Studio Solution

  1. Run Visual Studio with Administrator privileges.
  2. From the Start page, click New Project; or from the File menu, go toNew and select Project.
  3. Under Installed Templates in the New Project dialog box, expand Visual C#, and then click Windows.

Select the Console Applicationtemplate and name the projectContactManager.

Figure 2

Creating a new Console Application project

  1. Add assembly references:
  2. From the Project menu, select Add Reference.
  3. Select the following assemblies:

System.ServiceModel

System.ServiceModel.Activation

System.ServiceModel.Web

  1. Click Add.
  2. Click Close.

Figure 3

Adding assembly references

Note: As these assemblies are not included in the client profile, the project will be retargeted tothe full profile of .NET Framework 4.5.

  1. Add references to the WCF Web API assemblies.
  2. In Solution Explorer, right-click the project node and select Manage NuGet Packages.

Note: If this menu item does not appear, make sure that you installedNuGet Package Manager.You may need to restart Visual Studio.

  1. In the left pane, select “NuGet official package source” from theOnline section.
  2. In the Search box, type “webapi”.
  3. After the search completes, select the WebApi package and click Install.
  4. Click I Accept to accept the license for the WCF Web API libraries.
  5. After the package is installed, click Close.

Figure 4

Using NuGet to install the WebAPI assemblies

Task 3 — Define the Contact Resource

RESTful APIs are all about resources. For the Contact Manager, we will define a single resource type—the contact resource. For this lab, a contact resource will consist of a contact name plus an identifier. For example:

Contact ID / Contact Name
“1” / “Alice”
“2” / “Bob”

In a real application, contacts would include more information, such as email address, phone number, and so on. But adding these extra fields would not really add anything to the lab, so we’ll keep things simple.

To define the contact resource, add a new Contact class to the project.

  1. In Solution Explorer, select the project.
  2. From the Project menu, selectAddClass.
  3. Name the class file Contact.cs.
  4. Add the public modifier to the class.
  5. Add the following properties to the Contact class.

(Code Snippet – WCF Web API Lab - Ex01 - Contact Class - CS)

C#

publicclassContact

{

publicint Id { get; set; }

publicstring Name { get; set; }

}

Task 4 — Create the Contact Repository

Our service needs a place to store contacts. For this exercise, contacts will be stored in system memory.

  1. From the Project menu, select AddClass.
  2. Name the classfile ContactRepository.cs.
  3. Add the public modifier to the class.

C#

publicclassContactRepository

{

}

  1. Add the following class implementation.

(Code Snippet – WCF Web API Lab - Ex01 - ContactRepository Class - CS)

C#

public classContactRepository

{

private intnextID = 1;

privateListContact> contacts = newListContact>();

publicvoid Add(Contact contact)

{

if (contact == null)

{

thrownewArgumentNullException("contact");

}

if (contact.Id == 0)

{

contact.Id = this.nextID;

this.nextID++;

}

this.contacts.Add(contact);

}

publicvoid Delete(Contact contact)

{

if (contact == null)

{

thrownewArgumentNullException("contact");

}

this.contacts.Remove(contact);

}

publicListContactGetAll()

{

returnthis.contacts;

}

publicContactGetById(int id)

{

returnthis.contacts.Find((x) => x.Id == id);

}

}

  1. For this lesson, the contact service will be read-only, so we need to populate the repository with some names. In the ContactRepositoryclass, add the following constructor.

(Code Snippet – WCF Web API Lab - Ex01 - ContactRepository Constructor - CS)

C#

publicContactRepository()

{

this.Add(newContact() { Name = "Alice" });

this.Add(newContact() { Name = "Bob" });

this.Add(newContact() { Name = "Charles" });

this.Add(newContact() { Name = "Denise" });

}

Feel free to make up your own names. Notice that the Add method overwrites the contact ID using a running counter (the nextID variable).

Task 5 — Create the Contact Service

In this task, you will define a service contract by using WCF WebApi. Then, you will add a service method, which will return all the contacts and a single contact by its id.

  1. Add a new C# class named ContactService.
  2. Add the public modifier to the class.
  3. Add the following using statements.

(Code Snippet – WCF Web API Lab - Ex01 - Service Namespaces - CS)

C#

using System.Net;

usingSystem.Net.Http;

usingSystem.ServiceModel;

usingSystem.ServiceModel.Activation;

usingSystem.ServiceModel.Web;

usingMicrosoft.ApplicationServer.Http.Dispatcher;

  1. Add the [ServiceContract]attribute to the ContactService class.

C#

[ServiceContract]

publicclassContactService

{

...

The ServiceContract attribute defines a WCF service contract. The WCF runtime uses this attribute to bind to the service.

  1. Add a static field that contains a ContactRepository instance.

(Code Snippet – WCF Web API Lab - Ex01 - Service Store - CS)

C#

[ServiceContract]

publicclassContactService

{

privatestaticContactRepository store = newContactRepository();

...

  1. Add the following methods to the class:

(Code Snippet – WCF Web API Lab - Ex01 - Service Methods - CS)

C#

[WebGet(UriTemplate = "/contacts")]

publicListContactGetAllContacts()

{

returnstore.GetAll();

}

[WebGet(UriTemplate = "/contacts/{id}")]

publicContactGetContact(int id)

{

Contactcontact = store.GetById(id);

if (contact == null)

{

thrownewHttpResponseException(HttpStatusCode.NotFound);

}

returncontact;

}

The WebGet attribute exposes the method to clients as an HTTP GET method. The UriTemplate parameter defines the URL for the method. For example, to invoke the GetAllContacts method, the client would send and HTTP GET request to url/contacts/, where url is the base URL of the service. The base URL will be defined in the next task.

Task 6 — Host the Service

In this task, you will host the service locally using the HttpServiceHost class, in order to access each operation in the specified address.

  1. Open the code file Program.cs.
  2. Add the following using statement in order to use the HttpServiceHost class, which provides a ServiceHostto host the HTTPservice.

(Code Snippet – WCF Web API Lab - Ex01 -Host Using - CS)

C#

usingMicrosoft.ApplicationServer.Http;

  1. Add the following code to the Main method. The service of type ContactServicewill run in the URL and port you are specifying.

(Code Snippet – WCF Web API Lab - Ex01 -Host Main - CS)

C#

staticvoid Main(string[] args)

{

using (var host = newHttpServiceHost(typeof(ContactService), "

{

host.Open();

Console.WriteLine("Press [enter] to Quit.");

Console.ReadLine();

}

}

Task 7 — Use the Browser to View the Contacts

  1. Start the application: Press F5, or choose Start Debugging from the Debug menu.

Note: If you receive the following error, make sure that you started Visual Studio with administrator privileges: “HTTP could not register URL If not, restart Visual Studio with administrator privileges and open the project again.

  1. Open a browser window.
  2. In the address bar, type / and press Enter. You should see an XML representation of the contact list.

Figure 5

Contact list displayed in the browser window

  1. In the address bar, type and press Enter. You should see an XML representation of a single contact.
  2. Close the browser window and press Enter in the console application to stop debugging.

Discussion

To expose a GET method from a WCF Web API service, just add the WebGet attribute to a public method of the service class. For example, the GetAllContacts method was defined as follows:

C#

[WebGet(UriTemplate = "/contacts")]

publicListContactGetAllContacts()

{

returnStore.GetAll();

}

The UriTemplate parameter gives the URI of the HTTP GET method, relative to the base path listed in the routing information (see Task 2).

The base path for our service is , so the URI template “/contacts” corresponds to . If a client requests this URI, the GetAllContacts method is invoked.

The URI template can also be parameterized, as shown in the GetContact method:

C#

[WebGet(UriTemplate = "/contacts/{id}")]

publicContactGetContact(int id)

{

...

The id parameter within the curly braces is bound to the method parameter of the same name. For example, if the client requests , the GetContact method is invoked with a value of 1 for the id parameter.

Notice that both of these methods return CLR types. The Web API automatically serializes the return value. The default serialization format is XML. In the next exercise, you’ll see how a client can request JSON by providing an Accept header in the HTTP request.

Task 8 — Create a Client Application

In this task, you will create a client application that will use the WCF WebApi service that you have worked on.

  1. Add a new console application to the solution.
  2. From the File menu, select Add and then New Project.
  3. Expand the Visual C# project types and select Windows, then Console Application.
  4. Name the project ContactClient.
  5. Change the target framework to .NET Framework 4.5.
  6. In Solution Explorer, right-click the ContactClient project and select Properties.
  7. In the Target framework dropdown list, select .NET Framework 4.5.
  8. Click Yes.

Figure 6

Setting the target framework

  1. Add references to the WCF Web API assemblies.
  2. In Solution Explorer, right-click the ContactClientproject and select Manage NuGet Packages.
  3. In the pane on the left, select Recent Packages.
  4. Select WebApi.
  5. Click Install.
  6. Click Close.

Note: These steps assume that you already installed the WebApi package in Task 2.

  1. Add a reference to the ContactManager project:
  2. From the Project menu, select Add Reference.
  3. Select Solution.
  4. Click Add.
  5. Click Close.

Figure 7

Adding a reference to the ContactManager project

  1. OpenProgram.cs located under the ContactClient project. Add the following using statements.

(Code Snippet – WCF Web API Lab - Ex01 -Client Namespaces - CS)

C#

usingSystem.Net.Http;

usingSystem.Web;

usingContactManager;

  1. Add the following static method.

(Code Snippet – WCF Web API Lab - Ex01 -ListAllContacts - CS)

C#

privatestaticvoidListAllContacts(HttpClient client)

{

client.GetAsync("api/contacts")

.ContinueWith(r =>

{

Console.WriteLine("List Status: {0}", r.Result.StatusCode);

if (r.Result.IsSuccessStatusCode)

{

r.Result.Content.ReadAsAsyncListContact>()

.ContinueWith(l =>

{

foreach (Contact c inl.Result)

{

Console.WriteLine("{0}: {1}", c.Id, c.Name);

}

});

}

});

}

  1. Add the following code to the Main method.

(Code Snippet – WCF Web API Lab - Ex01 -Client Main - CS)

C#

staticvoid Main(string[] args)

{

using (HttpClient client = newHttpClient())

{

client.BaseAddress = newUri("

ListAllContacts(client);

Console.WriteLine("Press [enter] to quit.");

Console.ReadLine();

}

}

  1. Press F5 to start debugging the ContactManager project.
  2. Run the ContactClient client project:
  3. In Solution Explorer, right-click the ContactClient project.
  4. Select Debug and then Start New Instance.
  5. The console application should run, displaying a list of contacts.

Figure 8

Running the ContactClient application

  1. Press Enter in both console applications to stop debugging.

Discussion

The HttpResponseMessage object represents an HTTP response. You can use it to get the status code, headers, and message body of the request. HttpResponseMessage also has a generic ReadAsAsync<T> method that deserializes the message body into a CLR type, so that you don’t have to worry about serialization formats.

If you want to see the message body in its original form, replace the if statement with the following:

(Code Snippet – WCF Web API Lab - Ex01 -ReadAsString - CS)

C#

if (r.Result.IsSuccessStatusCode)

{

r.Result.Content.ReadAsStringAsync()

.ContinueWith(s =>

{

Console.WriteLine(s.Result);

});

}

Now if you re-run the client, it will output the following:

XML

<?xml version="1.0" encoding="utf-8"?<ArrayOfContactxmlns:xsi=" xmlns:xsd="

As you can see, the web service defaulted to XML serialization. The client can request JSON format by adding an Accept header with the value “application/json”:

C#

using (HttpClient client = newHttpClient())

{

client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

client.BaseAddress = newUri("

ListAllContacts(client);

Now if you run the application, the HTTP response contains the following:

JSON

[{"Id":"1","Name":"Alice"},{"Id":"2","Name":"Bob"},{"Id":"3","Name":"Charles"},{"Id":"4","Name":"Denise"}]

Exercise 2: Create a Read/Write Service

In Exercise 1, you created a read-only service. In this exercise, you will add methods to create, delete and update contacts.

Task 1 — Add a Method to Create New Contacts

  1. Open the ContactService.cs code file and add the following method to the ContactService class.

(Code Snippet – WCF Web API Lab - Ex02 -CreateContact - CS)

C#

[WebInvoke(UriTemplate = "/contacts", Method = "POST")]

publicHttpResponseMessageContactCreateContact(HttpRequestMessageContact> request)

{

if (request == null)

{

thrownewArgumentNullException("request");

}

HttpResponseMessageContact> response = null;

vartask = request.Content.ReadAsAsync();

task.Wait();

Contactcontact = task.Result;

if (contact == null)

{

response = newHttpResponseMessageContact>(HttpStatusCode.BadRequest);

}

else

{

store.Add(contact); // Add the new contact to the repository.

response = newHttpResponseMessageContact>(contact, HttpStatusCode.Created); // status = 201

response.Headers.Location = newUri(request.RequestUri, contact.Id.ToString());

}

return response;

}

Task 2 — Add a Method to Delete Contacts

  1. To enable the user to delete a contact, add the following method to the ContactService class.

(Code Snippet – WCF Web API Lab - Ex02 -DeleteContact - CS)

C#

[WebInvoke(UriTemplate = "/contacts/{id}", Method = "DELETE")]

publicContactDeleteContact(int id)