Posts
201
Comments
1111
Trackbacks
51
WCF Web API is Pure Simplicity with NuGet

Last week at MIX11, Preview 4 of WCF Web API was released. If you missed it, you can watch the video here. One way to get Preview 4 and start playing with it is to download it here. However, an even easier way to to just grab the bits from NuGet:

 

webapinugetdiag

 

When you download the latest Web API bits, there are a couple of sample applications that show off the latest features of the Web API (these are in the CodePlex download, not the NuGet packages). The first one is a Contact Manager “Simple” project which is intended to show just how simple it is to consume the Web API framework. There is also another sample which shows the advanced features such as IoC support, custom media type formatters, channels, and more.

I like to create a lot of “Hello World” applications when I’m learning a new technology for the first time or even when I just want to do some quick tests for a technology I already know pretty well. The existing Web API NuGet packages certainly help us add the references quickly. However, there is an even quicker way to get up and running with the new Web API – sample NuGet packages. Since NuGet has such rich functionality beyond adding references such as adding start code and configuration, there are many packages that exist to get you up and running fast. David Ebbo highlighted this last month in his post: Take NuGet to the next level with sample packages.

Taking all this into account, I created a “WebApi.CrudHttpSample” NuGet package. This allows you to fire up a brand new instance of Visual Studio, File – New Project, add the package and you are up and running. The Web API assemblies are added via NuGet dependencies and starter code is added as well. You can just select an “ASP.NET Empty Web Application” without having to worry about selecting some special WCF project template. This will have nothing in it but an empty web.config file.  Now you can add the package:

PM> Install-Package WebApi.CrudHttpSample

This first thing you’ll see is a “dummy” model class that looks like this:

   1:  // TODO: Use Visual Studio refactoring to rename "MyModelType" to your desired type.
   2:  //       Then you can move the model to its own file.
   3:  public class MyModelType
   4:  {
   5:      public int Id { get; set; }
   6:  }

Use Visual Studio refactoring to rename this class. It’s important to use the VS.NET refactoring because the type is referenced elsewhere in the starter code so this will rename it appropriately everywhere. I’ll rename it to “Contact” and add a couple of properties to it:

   1:  public class Contact
   2:  {
   3:      public int Id { get; set; }
   4:      public string FirstName { get; set; }
   5:      public string LastName { get; set; }
   6:  }

The next thing you’ll see is a resource class called “MyModelResource”. Again, you should use VS.NET refactoring to rename it to something that is sensible for your application. I’ll rename it to “ContactResource” (this is a similar approach to the starter code in the REST Start Kit from a couple years ago – of course they didn’t have NuGet at their disposal!). The code looks like this:

   1:  [ServiceContract]
   2:  public class ContactResource
   3:  {
   4:      // TODO: replace with your own "real" Repository implementation
   5:      private static readonly Dictionary<int, Contact> repository = new Dictionary<int, Contact>();
   6:   
   7:      [WebGet(UriTemplate = "{id}")]
   8:      public HttpResponseMessage<Contact> Get(int id)
   9:      {
  10:          Contact item;
  11:          if (!repository.TryGetValue(id, out item))
  12:          {
  13:              var notFoundResponse = new HttpResponseMessage();
  14:              notFoundResponse.StatusCode = HttpStatusCode.NotFound;
  15:              notFoundResponse.Content = new StringContent("Item not found");
  16:              throw new HttpResponseException(notFoundResponse);
  17:          }
  18:          var response = new HttpResponseMessage<Contact>(item);
  19:   
  20:          // set it to expire in 5 minutes
  21:          response.Content.Headers.Expires = new DateTimeOffset(DateTime.Now.AddSeconds(30));
  22:          return response;
  23:      }
  24:   
  25:      [WebInvoke(UriTemplate = "", Method = "POST")]
  26:      public HttpResponseMessage<Contact> Post(Contact item)
  27:      {
  28:          item.Id = (repository.Keys.Count == 0 ? 1 : repository.Keys.Max() + 1);
  29:          repository.Add(item.Id, item);
  30:   
  31:          var response = new HttpResponseMessage<Contact>(item);
  32:          response.StatusCode = HttpStatusCode.Created;
  33:          response.Headers.Location = new Uri("Contacts/" + item.Id, UriKind.Relative);
  34:          return response;
  35:      }
  36:   
  37:      [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
  38:      public Contact Put(int id, Contact item)
  39:      {
  40:          repository[id] = item;
  41:          return item;
  42:      }
  43:   
  44:      [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
  45:      public Contact Delete(int id)
  46:      {
  47:          var deleted = repository[id];
  48:          repository.Remove(id);
  49:          return deleted;
  50:      }
  51:  }

There are several things to note about this code. First, I’m just using a static Dictionary for temporary storage. This can be replaced with your “real” repository of choice. The Get() method returns an HttpResponseMessage which is the strongly typed HTTP message available in the Web API. You can see that if the id is not found, we’re able to throw an HttpResponseException which is a much more intuitive way of dealing with exceptions than what we have today. I’m also able to set expiration headers – all without referring to the static WebOperationContext. The other methods are similarly easy to work with. It’s important to point out that this is not a RESTful service – this is merely a CRUD service over HTTP. Although I do set the location header in the Post() method, I’m not leveraging hypermedia and therefore, not RESTful.

At this point, all I have is a single C# file – how do I get this hooked into the WCF pipeline? The next thing I take advantage of is the WebActivator NuGet package. I follow the established pattern for the “App_Start” folder and put my initialization code in here. This code will automatically be invoked when the web site starts up (no need for Global.asax). Then just change the first URI segment from “MyModel” to whatever you want. I’ll change it to “Contacts”:

webapiappstart

At this point, I can now run my app in Fiddler with all VERBs:

  • GET /Contacts/1 – gets an existing contact (404 if it doesn’t exist)
  • POST /Contacts – specify Content-type: application/type and post Contact xml to insert
  • PUT /Contacts/1 – updates existing Contact
  • DELETE /Contacts/1 – deletes existing Context

To see the NuGet package in action as well as executing all methods in Fiddler, watch this short (6 minute) video below (if there is a problem with the embedded video, direct video link is here):

Viewing this content requires Silverlight. You can download Silverlight from http://www.silverlight.net/getstarted/silverlight3.

A logical next step would be to create a NuGet sample package that contains starter code for more advanced features such as IoC, media type formatters, etc. The Web API is getting better and better. It’s now easier and simpler than ever to work with HTTP. Now is the time to start getting familiar with it and provide your feedback to the team.

posted on Thursday, April 21, 2011 2:49 AM Print
Comments
Gravatar
# re: WCF Web API is Pure Simplicity with NuGet
Steve Gentile
4/22/2011 7:53 AM
"Although I do set the location header in the Post() method, I’m not leveraging hypermedia and therefore, not RESTful."

Would love to see a post from you that leverages hypermedia to demonstrate how that makes it truly 'RESTful'

Thanks - great post! Like to see how you have combined nuget packages, web activator, etc..
Gravatar
# re: WCF Web API is Pure Simplicity with NuGet
Matt
4/27/2011 8:45 PM
Steve,

Great post. I tried following along the example you provided and I get the following exception. I have Visual Studio 2010 SP1 currently installed on my machine. Any help would be welcome.

[TypeLoadException: Could not load type 'Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility' from assembly 'Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'.]
WebActivator.ActivationManager.Run() +0

[InvalidOperationException: The pre-application start initialization method Run on type WebActivator.ActivationManager threw an exception with the following error message: Could not load type 'Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility' from assembly 'Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'..]
System.Web.Compilation.BuildManager.InvokePreStartInitMethods(ICollection`1 methods) +423
System.Web.Compilation.BuildManager.CallPreStartInitMethods() +306
System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +677

[HttpException (0x80004005): The pre-application start initialization method Run on type WebActivator.ActivationManager threw an exception with the following error message: Could not load type 'Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility' from assembly 'Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'..]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +8972180
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +97
System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +258
Gravatar
# re: WCF Web API is Pure Simplicity with NuGet
Steve
4/28/2011 11:28 AM
@Matt - Sounds like you're hitting this problem: http://social.msdn.microsoft.com/Forums/en-CA/orchardsupport/thread/3a64d512-2d3e-4ca9-bb96-72288100f9ee
Gravatar
# re: WCF Web API is Pure Simplicity with NuGet
Lei
5/7/2011 9:17 PM
Good example, good packaging. Why we did not have this before? :-)
Gravatar
# re: WCF Web API is Pure Simplicity with NuGet
Alexsandro
7/10/2012 9:14 PM
You said: It's not a RESTFul services, why not could considered?
Gravatar
# re: WCF Web API is Pure Simplicity with NuGet
Steve Michelotti
7/10/2012 9:32 PM
@Alexsandro - To be considered "truly" RESTful, the Web API must be hypermedia driven - http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

Post Comment

Title *
Name *
Email
Comment *  
 

View Steve Michelotti's profile on LinkedIn

profile for Steve Michelotti at Stack Overflow, Q&A for professional and enthusiast programmers




Google My Blog

Tag Cloud