Announcement: WCF Web API is now ASP.NET Web API! ASP.NET Web API released with ASP.NET MVC 4 Beta. The WCF Web API and WCF support for jQuery content on this site wll removed by the end of 2012.

Getting Started: Building a simple Web API

Learning objectives

In this quick start you will learn the basics of how you use WCF Web API with ASP.NET MVC 3*

  • How to add Web API to an existing project using NuGet
  • How to create a new Web API which can be access through an HTTP GET
  • How to host a Web API through ASP.NET routes
  • How to query a Web API via the browser or using the Web API test client
  • How to enable support for the OData URI queries with your APIs.

*Note: Web API does not requires ASP.NET MVC - it supports multiple hosting configurations including self-host, IIS and ASP.NET (both MVC and Web Forms). This quick start however shows how to host in ASP.NET MVC 3.

Pre-requisites

  • Visual Studio 2010 / Visual Studio 2010 SP1
  • ASP.NET MVC 3

Code

You can download the solution for this workshop here.

Scenario

For this quick start the scenario will be building  a simple Web API for managing contacts. The application will be consumed by one or more clients and will allow both retrieval of existing contacts as well as creation of new contacts.

1 – Creating the basic solution

  • Launch Visual Studio 2010
  • File->New Project->ASP.NET MVC 3 Web Application
  • Choose ContactManager as the name and specify the location, press “OK”

image

  • Choose “Empty” and click “OK”. An a new ASP.NET MVC 3 solution will be created.
  • Right click on the project and choose “Properties”. When the dialog pops up go to the “Web” option.
  • Go to the “Servers” section and choose “Specific port” specifying 9000 as the port.

image 

2 – Adding Web API to the solution

The next step will be to use NuGet to bring in the Web API binaries.

  • Right click on the project and select “Manage NuGet Packages”

image

  • The “Manage NuGet Packages” dialog will show. Select the “Online” option on the left. Then go to the search box and type “webapi.all”

image

  • Click the “Install” button. NuGet will go and download all of the necessary packages.
  • You will notice several Web API references will get added to your project.
  • You are now ready to go develop your Web API!

Note: The WebApi.All package includes the WebApi.Enhancements package that provides additional prototype features and components that can simplify your Web API implementation. These enhancements will be covered in a separate quick start. This quick start focuses on the core Web API functionality.

3 – Creating the Contacts API class

  • Right click on the ContactManager project and select Add->New Folder from the menu. Choose “APIs” as the folder name and hit “Enter”
  • Right click on the APIs folder and choose Add->Class. Enter “ContactsApi” as the class name.
  • Copy the code below into the new class.
using System.ServiceModel;

namespace ContactManager.APIs
{
    [ServiceContract]
    public class ContactsApi
    {
    }
}

The ServiceContractAttribute indicates to Web API that this class should be exposed over HTTP. Notice a using statement is added for “System.ServiceModel” which is where that attribute lives.

4 – Registering the Contacts API via routing

Our API needs to be hosted. In order to do this you will register it as an ASP.NET Route using ServiceRoute.

  • Switch to the global.asax.cs file.
  • Add the following two using statements at the top
using ContactManager.APIs;
using System.ServiceModel.Activation;
  • In the RegisterRoutes method add the following line to register a route for your new Web API.
routes.Add(new ServiceRoute("api/contacts", new HttpServiceHostFactory(), typeof(ContactsApi)));

Add the entry as show below. This is important because MVC’s default route matches the first part of the URI as representing a controller. In this case our API does not correspond to a controller + action combo thus we place it first.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.Add(new ServiceRoute("api/contacts", new HttpServiceHostFactory(), typeof(ContactsApi)));

    routes.MapRoute(
        "Default", // Route name
        "{controller}/{action}/{id}", // URL with parameters
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );
}

ServiceRoute takes a path for the API which will be appended to the IIS base address as well as the host factory to use and the type of the API. In this case we specified “contacts” thus is will be hosted at “http://localhost:9000/api/contacts”. Notice that contacts sits under a URI segement of “api”. The reasoning for this is to avoid conflicts between MVC routes as this route will always capture all traffic that starts with “api”.

Note: ServiceRoute has a known issue with that causes it to interfere with ASP.NET MVC action link generation. To work around this issue use WebApiRoute in WCF Web API Enhancements instead.

5 – Exposing contacts over an HTTP GET method.

In this part you will first create a POCO (Plain Old C#) Contact class which will contain the contact information that is passed back and forth between the API. It is essentially a DTO (Data Transfer Object) but in HTTP we consider the entity which is being represented a “Resource”. You will then create a handler method for exposing that resource as an HTTP GET. This will allow multiple clients to access the resource.

  • Right click on the ContactManager project and select Add->New Folder from the menu. Choose “Resources” as the folder name and hit “Enter”
  • Create a new “Contact” class. Copy the code below into the class.
namespace ContactManager.Resources
{
    public class Contact
    {
        public int ContactId { get; set; }
        public string Name { get; set; }
    }
}
  • Now switch back to the ContactsApi class. Add the two using statements below:
using System.ServiceModel.Web;
using ContactManager.Resources;
  • Now go implement a Get operation for retrieving all contacts by copying the code below.
[WebGet(UriTemplate = "")]
public IEnumerable<Contact> Get()
{
    var contacts = new List<Contact>()
        {
            new Contact {ContactId = 1, Name = "Phil Haack"},
            new Contact {ContactId = 2, Name = "HongMei Ge"},
            new Contact {ContactId = 3, Name = "Glenn Block"},
            new Contact {ContactId = 4, Name = "Howard Dierking"},
            new Contact {ContactId = 5, Name = "Jeff Handley"},
            new Contact {ContactId = 6, Name = "Yavor Georgiev"}
        };
    return contacts;
}
The WebGet attribute on the Get method indicates to Web API that this is to be exposed as an HTTP GET. Notice the UriTemplate is explicitly set to “”. By default the URI segment for the operation will be the method name. In this case we are building a RESTful resource such that the URI segment will be the Web API itself as defined in the route.

6 – Retrieving contacts in the browser

  • Double-click on the Properties node for the project and select the Web tab
  • In the Start Action section select the Specific Page radio button and enter “api/contacts” in the corresponding text box
  • Press F5 to launch the application
  • When the browser finishes loading you will see the contact list returned as shown below.

image

7 – Test the Contacts API

Web API supports an integrated test client that can be used to test the Web API functionality. The Web API test client is enabled through configuration.

  • In the RegisterRoutes method create an HttpConfiguration instance and set the EnableTestClient property to true.
var config = new HttpConfiguration() { EnableTestClient = true };
  • Pass the configuration instance to the HttpServiceHostFactory for the Web API route by setting the Configuration property.
routes.Add(new ServiceRoute("api/contacts", new HttpServiceHostFactory() { Configuration = config }, typeof(ContactsApi)));
  • Press F5 and append “/test” to the browser address to bring up the Web API test client

image

  • Click on the Contacts API URI in the Resources view to populate the Request fields for a simple GET request

image

  • Click the Send button the issue the GET request and view the response

image

8 – Retrieving contacts in JSON

Web API supports what is known in HTTP as server driven content negotiation (conneg). This means clients can send an accept header in the HTTP request indicating alternative media types than XML which they would like the response to be returned in. Web API also makes it very easy to add support for new media types, or to even replace the defaults. This will be covered in a future quick start.

  • Browse to the Web API test client for the Contacts API if it is not still open
  • Click on the Contacts API URI in the Resources view to populate the Request fields for a simple GET request
  • Modify the Accept header value to be  “application/json”

image

Notice the Web API test client provides IntelliSense for common media types

  • Click the Send button to issue the Request and see the Response formatted as JSON

image

9 – Enabling OData query support

Web API supports the ability to accept a subset of the OData query URI format ($top, $skip, $orderby, and $filter). When an OData query request is received, Web API will apply the necessary filtering and ordering on the result before it is returned to the client. It composes queries using IQueryable thus the server does not have to query all the data and can send a filtered query to the data source.

  • Stop the application if it is running.
  • Switch to ContactApi.cs.
  • Add the following using statement
using System.Linq;
  • Modify the Get method to return IQueryable<ContactResource>.
[WebGet(UriTemplate = "")]
public IQueryable<Contact> Get()
{
    var contacts = new List<Contact>()
        {
            new Contact {ContactId = 1, Name = "Phil Haack"},
            new Contact {ContactId = 2, Name = "HongMei Ge"},
            new Contact {ContactId = 3, Name = "Glenn Block"},
            new Contact {ContactId = 4, Name = "Howard Dierking"},
            new Contact {ContactId = 5, Name = "Jeff Handley"},
            new Contact {ContactId = 6, Name = "Yavor Georgiev"}
        };
    return contacts.AsQueryable();
}
  • Run the application.
  • Once the browser page loads, append the query string “?$top=4&$orderby=Name” to the address and press enter.
  • The top four contacts are returned ordered by name.

image

  • Browse to the test client and issue the same request with the same query string, but specify “application/json” in the Accept header
  • Click the Send button and results are returned in JSON.

image

Summary

In this quick start we learned the following:

  • How to add the Web API NuGet package (WebApi.All) to an existing project in order to use Web API.
  • How to create a new Web API and host it over an HTTP GET Method
  • How to return a resource from a Web API that can be represented in multiple formats
  • How to retrieve data from a Web API in different formats by using the HTTP Accept header.
  • How to enable OData query support.

Last edited Feb 17, 2012 at 7:33 PM by danroth27, version 23

Comments

Dharnishr Apr 11, 2012 at 8:28 PM 
This example with MVC3 and Webapi.all is having some minor problem

a) Step 2 is not working:

Precondition: i) Need to have nuget
ii) Visual Studio 2010 (Express or Professional)
Solution: Install-Package WebApi.All -Version 0.6.0

b) MVC3 pages will stop working. (The solution provided dont have MVC page)
Problem: Form Action will start pointing to "api/contacts"
Solution:
In Global.asax, replace old one with below code.

routes.Add(new WebApiRoute("api/contacts", new HttpServiceHostFactory() { Configuration = config }, typeof(RegionsService)));

Create a new class.

public class WebApiRoute : System.ServiceModel.Activation.ServiceRoute
{
public WebApiRoute(string routePrefix, ServiceHostFactoryBase serviceHostFactory, Type serviceType): base(routePrefix, serviceHostFactory, serviceType)
{

}

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return null;
}

Note: i) Reference:
http://codebetter.com/glennblock/2011/08/05/integrating-mvc-routes-and-web-api-routes-2/
ii) In reference, constructor is wrong.

Happy => Happy.VS2010.MVC3
-Dharnish

legos211 Feb 5, 2012 at 8:15 PM 
I have been working through the WCF samples with the goal of using WCF Web Api for a new project. I quickly ran into challenges with Entity Framework (EF). It seams the WCF Web Api doesn't support POCO classes that have been used in an EF repository.

The only solution I found was to disable lazy loading by adding:

public MyProjectDbContextConstructor()
: base()
{
this.Configuration.ProxyCreationEnabled = false;
}

This obviously loses the ability to access any related objects.

Is this by design? Is there a good resource for using the Web API with EF? Am I just missing something in how I am coding my project?

Craig Anderson

davescruggs Jan 24, 2012 at 11:21 PM 
I haven't been able to get the OData feed to work with LinqPad or with Excel PowerPivot. I get validation errors. Is there something else I should do?

identofnoident Jan 13, 2012 at 1:43 PM 
@gblock Hell. Yeah.

johnvpetersen Jan 13, 2012 at 12:43 PM 
Nice example. I went ahead and posted code to turn this MVC example into a self-hosted example. You can find the code here: http://codebetter.com/johnpetersen/2012/01/13/webapi-developer-preview-6-self-hosted-mode-example/.

Saf Jan 4, 2012 at 5:56 PM 
In section 7, global.asax.cs, you also need to add the namespace "Microsoft.ApplicationServer.Http" for the HttpConfiguration().

rcurlette Dec 12, 2011 at 10:05 AM 
In section 4, global.asax.cs, you also need to add the namespace "Microsoft.ApplicationServer.Http.Activation" for the HttpServiceHostFactory()

ygorthomaz Dec 4, 2011 at 5:49 PM 
Excellent project. Thanks!

petersmith Nov 25, 2011 at 8:09 AM 
Im getting an error when opening your code files in Visual Studio 2010, also see my post on it here: http://forums.asp.net/p/1743303/4700104.aspx/1?Re+Visual+Studio+2010+The+project+type+is+not+supported+by+this+installation+
If possible could you report the code files?
Thanks!

hungvu Nov 18, 2011 at 5:35 PM 
Simple tutorial that showed the power of WCF Web API! Can't wait to start using it in production. Thanks Microsoft's team.

Rushmi Nov 15, 2011 at 4:09 PM 
excellent work !!!!

CmdrBeavis Nov 7, 2011 at 3:27 PM 
I am happy to say that I built this sample from the ground up, and it all ran great! Thanks for all your hard work Glenn, et al. :D

fljohwat Oct 12, 2011 at 9:05 PM 
I did this exercise, but returned some data from an EF model rather than the hard coded resources. Works great in browser and in test client, but when I change the accept header to application/json, I get response 12152/Unknown.

wbott70 Oct 2, 2011 at 8:52 PM 
This is really great. Thanks for all your efforts to the folks that lead the charge on this. Absolutely needed this.

smarchetti Sep 15, 2011 at 6:26 PM 
Very cool preview 5. I love the OData support. Can you point me in the right direction for return odata as json?

The_Coder Sep 6, 2011 at 12:09 PM 
I tried the sample, the basic ODATA query works, but things like substringof or length is not working. Is this a limition?

0bscur3 Sep 2, 2011 at 8:58 PM 
(Sorry for my bad english)
I follow the tutorial and all is working great but what do I need to do to be able to use $select on the query? Something like this:
http://localhost:9000/api/contacts?$select=Name
should return only the Name but are returning all fields.

lafama Jul 21, 2011 at 6:56 AM 
hi,
Am unable to run and access this service if i sent the trust level to Medium please help

groovq Jul 6, 2011 at 12:40 AM 
how would you return JSONP? and call via JQuery from another site?

DennisvandeLaar Jun 28, 2011 at 12:16 PM 
Great walkthrough. One minor thing is that we have added a class (resource) Contact and not ContactResource. At part VI we have to modify the get method:
"Modify the Get method to return IQueryable<ContactResource>" --> The name of the class should be renamed to ContactResource or change to IQueryable<Contact>.

Like i mentioned a minor thing. Thanks for the walkthrough!!

kcs Jun 26, 2011 at 7:07 AM 
@gblock
Yes Glenn, that seems to be the case.

@dfowler
Cool, thanks for the heads-up, I thought I may have just been doing it wrong. NuGet has been great to use.

dfowler Jun 26, 2011 at 6:31 AM 
@kcs This is a bug in nuget. We're going to be fixing it in 1.5.

gblock Jun 26, 2011 at 6:22 AM 
@Kelly

So you are saying it works perfect as long as you go manage packages at the project level right?

kcs Jun 26, 2011 at 6:11 AM 
..
Thanks Glenn.

In the several tests I just performed I consistently get the same behavior of:

1) If I right-click on the PROJECT and use “Manage NuGet Packages…" then all references and the Web.config are setup and all works with WebApi.All as expected.

2) If I right-click on the SOLUTION and use “Manage NuGet Packages…" to add WebApi.All then the references are not added to the project, and packages.config and Web.config are not modified. If I manually re-launch “Manage NuGet Packages…" at the SOLUTION level, go to WebApi.Core, push the Manage button, and select the “ContactManager” project, then all things get wired up as expected.

So for me, using NuGet 1.4 at the project level is easiest for this sample.

This may be by design or it may just be my system that needs a reinstall. Oh well : )

Here is some system detail in case others have these issues and it warrants more troubleshooting:

Windows 7 Ultimate x64

Microsoft Visual Studio 2010
Version 10.0.40219.1 SP1Rel

Microsoft .NET Framework
Version 4.0.30319 SP1Rel

Installed Version: Premium
Microsoft Visual Studio 2010 Premium - ENU Service Pack 1 (KB983509) KB983509

NuGet Package Manager 1.4.20615.9020
NuGet Package Manager in Visual Studio. For more information about NuGet, visit http://docs.nuget.org/.

Thanks again!

gblock Jun 26, 2011 at 5:40 AM 
Hi Kerry

I sounds like I need to test this with the latest nuget as things that should work did not work for you.

1. On the "Manage NuGet Packages" thanks for the pointer. Others told me about that. They did not have the same problems you did though with the references.
2. You should not have to add any manual references. The nuget pack contains intstructions to add Gac'd references.
3. You should not have to modify the config as the nuget contains a transformation for modifying config.

Cheers
Glenn

kcs Jun 26, 2011 at 5:01 AM 
I really like the capabilities of WCF Web Api, thank you!

Here are some things I had to work through to use the example that may help others:

Part II
When you try this step:
[Right click on the solution and select “Add Library Package Reference”]

If you are using the latest NuGet (1.4) you will not see “Add Library Package Reference”.
You will see, “Manage NuGet Packages…" instead.

If you are using NuGet 1.4, although these instructions suggest that you right-click on the SOLUTION to use NuGet, I would recommend that for this example you right-click on the PROJECT “ContactManager” instead and select “Manage NuGet Packages…" from there.

Why? Because NuGet 1.4 added some new features to allow you to better manage multi-project solutions but on my system when I tried to add WebApi.All at the SOLUTION level, NuGet by default did NOT add the DLL references to the “ContactManager” project. In older versions of NuGet those references were added to my sub-projects automatically even if I used “Add Library Package Reference” at the solution level. I am not sure if this is just an issue on my machine but if you find yourself wondering why your using statements can’t be resolved or this example won’t run without throwing exceptions you may want to make sure that your “ContactManager” PROJECT actually has the many dll references that are currently required to use the WCF Web Api in its current state.

Some other things to be aware of that may not be obvious at first glance if you are new to WCF and the WCF Web Api like I am:

In Part III you need to manually add a reference to “System.ServiceModel” in the “ContactManager”project as it is part of the .NET Framework and not automatically referenced for you with NuGet.

In Part V you need to manually add a reference to “System.ServiceModel.Web” in the “ContactManager”project as it is part of the .NET Framework and not automatically referenced for you with NuGet.

In Part VI when I pressed F5 to launch the application I received an exception:
“InvalidOperationException” “ASP.NET routing integration feature requires ASP.NET compatibility.”
I had to add the following to the “ContactManager”’s Web.config file in order to run the application and continue on with the exercises.

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true">
</serviceHostingEnvironment>
</system.serviceModel>

No idea if that is the “correct” thing to do but it let me move on and complete the quick start which was my ultimate goal. Pretty cool stuff once I got it going. Thank again to the team!