Overview [Note this out of date and needs to be updated]

In this walkthrough you will see how to create a simple HTTP service which is accessible through a browser. The solution shows POSTing names to a Hello resource from an HTML page. When the same resource is accessed through a GET via a link it returns a message which says hello to all the names that were posted.

Below is a screen shot of the “application” running in a browser.

image 

Concepts covered within

  • How to create an ASP.NET project for hosting HTTP services
  • How to author an HTTP Service
  • How to host an HTTP Service with ASP.NET routes
  • How to expose service methods as HTTP methods
  • How to access the HTTP request and response
  • How to access content
  • How to use JsonValue to handle FormUrlEncoded content sent from an HTML Form.

Pre-installed dependencies for this solution

  • .NET 4.0
  • ASP.NET 4.0
  • WCF HTTP Source

Setting up the solution

Before getting started open the HTTP solution within the WCF HTTP source and build it. All binaries will be built to the /build/Debug/Http/bin folder off of the root folder where you extracted the solution.

  • Open Visual Studio and create a new solution by going to File->New Project->Web->ASP.NET Empty Web Application. Call the solution HelloResource.
  • Add the following .NET references
    • System.ServiceModel
      System.ServiceModel.Web
    • System.ServiceModel.Activation
  • Add the following WCF Web API references by browsing to the /build/Debug/Http/bin folder
    • Microsoft.Net.Http.dll
    • Microsoft.ServiceModel.WebHttp.dll
    • Microsoft.Runtime.Serialization.Json.dll
    • Microsoft.ServiceModel.Web.jQuery.dll
  • Open web.config. Replace the <configuration> node with the snippet below which enables the routing module and enables ASP.NET compatibility for WCF.
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
  </system.web>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
    </modules>
  </system.webServer>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>
</configuration>
  • Right click on the project and select “Add New Item”. Choose Global application class.
  • Right click on the project and select “Add New Item”. Choose “HTML Page” and set the name to default.html
  • Open default.html and replace the contents with the following markup
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <form action="hello" enctype="application/x-www-form-urlencoded" method="post" target="result">
        Enter a person to say hello to: <br />
        <input type="text" name="person" />
        <input type="submit" value="Submit" /> <br /><br />
        <a href="hello" target="result">Get hello resource</a> <br /><br />
        <iframe name="result" />
    </form>
</body>
</html>

The page above contains a form for posting a person’s name to the server. Notice it sets the method to post. This is because we are modifying the state of the resource by adding a new person, thus it is not an idempotent / safe operation. If we were retrieving we would have used GET the default. The page also contains a link for retrieving the hello resource through an HTTP GET. The results of both calls are returned in the result iframe.

Creating an HTTP service which works directly with HTTP messages

Creating the Hello resource

  • Right click on the project select “Add New Item”. Add a new class file and call it HelloResource.cs.
  • Annotate the class with a [ServiceContract] and and add placeholders for the GET and POST methods.
[ServiceContract]
public class HelloResource
{
}
  • The service is annotated with a [ServiceContract]. This tells WCF this is a service.

Implementing the GET Method

  • Add the following snippet for the GET method to the HelloResource
private static List<string> peopleToSayHelloTo = new List<string>();
[WebGet(UriTemplate="")]
public void Get(HttpResponseMessage response)
{
    var body = "Hello " + string.Join(",", peopleToSayHelloTo);
    response.Content = new StringContent(body, Encoding.UTF8, "text/plain");
}
  • The Get method is annotated with a [WebGet] attribute. This tells WCF that this method response to an HTTP GET.
  • The UriTemplate is set to Empty in order to override the default of using the service name as part of the uri template. Because we will be using ASP.NET routes the route will specify the uri.
  • The method takes the the new System.Net.Http.HttpResponseMessage as a parameter in order to access the response. In prior versions of WCF you access the underlying HTTP message through the static WebOperationContent. Using this new approach removes the need for such static method calls and makes the code easier to test. The new apis are also more discoverable and offer a richer / strongly typed programming model for working with HTTP. *
  • The body of the method creates response content which contains which says hello to each person in the peopleToSayHelloTo list. This list will  be populated by the post. Note: Using static fields for holding state is just for illustration and is not the recommended way to build HTTP services.
  • The Content on the response is then set to a StringContent instance passing in the body, the encoding and the media type which is set to “text/plain”. There are several other content types included such as StreamContent which allows passing in a stream. HttpContent is abstract thus custom derived HttpContent classes can be created.

*WCF HTTP also supports serializing to and from types. The new APIs also allow you to plug in your own custom formatters very easily. More on type serialization in the topic “Exposing a service over HTTP using HTTP Messages”

Implementing the POST Method

  • Add the following snippet for the POST method to HelloResource
[WebInvoke(Method="POST",UriTemplate="")]
public void Post(HttpRequestMessage request, HttpResponseMessage response)
{
    var body = request.Content.ReadAsString();
    dynamic formContent = FormUrlEncodedExtensions.ParseFormUrlEncoded(body);
    var person = (string)formContent.person;
    peopleToSayHelloTo.Add(person);
    response.Content = new StringContent(string.Format("Added {0}", person), Encoding.UTF8, "text/plain");
}
  • The POST method is annotated with [WebInvoke] with the method set to “POST”.
  • It takes both HttpRequestMessage and HttpResponseMessage as it will access the posted content and return new content.
  • The content is parsed using a new extension method which returns a JsonObject instance. JsonObject is a dynamic dictionary for accessing Json or FormUrlEncoded content.
  • The response consists of a message indicating the person was added.
  • Return value is void as we are directly setting the response through the response object. WCF HTTP also support serializing to types.

Registering the HttpResource through ASP.NET Routes

  • Open Global.ASAX and paste the following into the Application_Start.
var config = new HttpHostConfiguration();
RouteTable.Routes.AddServiceRoute<HelloResource>("Hello", config);
  • This will register HelloResource with a base uri of “Hello”.
  • Notice an instance of HttpHostConfiguration is passed in. WCF HTTP adds a new api for configuring services through code. You can either new up an instance and configure it directly through it’s fluent interface, or derive from it to create a custom configuration class. We will use this instance when we get

Note: An instance of HttpHostConfiguration should not normally be required, however in the current bits there is a bug.

Running the application

  • Hit F5 to build and run the application.
  • The default web page will appear allowing you to enter in a name.
  • Enter a name and click submit.
  • The response frame will update with the message “Added {name}” where {name} will be the name that your post.
  • Enter another name and click submit.
  • The response frame will update with the message “Added {name}” where {name} will be the name that your post.
  • Click the “Get Hello Resource” link.
  • The response frame will update with a message that contains “Hello {name}” for each name you posted.

You’ve now seen how to use WCF HTTP to create an HTTP Service which exposes a resource which can be accessed by a browser.  We’ve also seen how to host HTTP services in ASP.NET through routes. We’ve seen how to access the raw HTTP content through the new HttpRequestMessage and HttpResponseMessage.

Last edited May 19, 2011 at 2:38 AM by gblock, version 4

Comments

johnsba1 Jun 14, 2011 at 9:16 PM 
Awesome. Just FYI to everyone that the samples included in the WCF Web API download contains working samples. If you run into any issues, take a look at those.

stevengentile May 21, 2011 at 1:43 PM 
Glenn, this is one of the few links on wcf web apis - I think it would be beneficial to get this update, or remove the link and link to something better. It creates alot of confusion... thanks

gblock May 19, 2011 at 2:37 AM 
This walkthrough is out of date and needs to get updated.

Tigraine May 15, 2011 at 7:07 PM 
@John042 : It seems they changed it from AddServiceRoute to MapServiceRoute and that extension Method is inside Microsoft.ApplicationServer.Http.Activation

mattdotson May 12, 2011 at 11:36 PM 
I can't find AddServiceRoute extension method anywhere. I'm using nuget as well.

hreisinger May 12, 2011 at 1:15 PM 
Unfortunately this does not work with the current NuGet-Version.

'System.Web.Routing.RouteCollection' does not contain a definition for 'AddServiceRoute' and no extension method 'AddServiceRoute' accepting a first argument of type 'System.Web.Routing.RouteCollection' could be found (are you missing a using directive or an assembly reference?)

Also JohnO42s Tip with creating a MVC2 Application does not help, neither creating a MVC3 Application helps. Any hints for me?

badams Mar 23, 2011 at 8:35 AM 
(insert) Creating Hello Service. Step #2 -> add using System.SericeModel to the top of HelloResource.cs

stevengentile Feb 23, 2011 at 4:01 AM 
ok, so there is a mismatch here between the nuget preview 3 and the download for preview 3. Nuget doesn't contain the FormUrlEncodedExtensions in the Microsoft.ServiceModel.Web.jQuery.dll assembly. Both say they are version 1.0.0.0 but there is obviously a mismatch here?

stevengentile Feb 18, 2011 at 6:43 PM 
I solved the StringContent by using response.Content = HttpContent.Create(body, Encoding.UTF8, "text/plain"); instead. Not sure on other two yet...

stevengentile Feb 18, 2011 at 6:35 PM 
This sample code above has references to classes that do not exist - at least through what I pulled down from nuget today.
ie. StringContent class. HttpHostConfiguration class. FormUrlEncodedExtensions. Is there an updated example anywhere ? This is a an official wcf.codeplex.com example correct?

gblock Feb 5, 2011 at 11:17 PM 
Thanks John, I updated the wiki.

JohnO42 Jan 27, 2011 at 3:29 PM 
OK - I figured out the problem (I think) - I had to start the above project with a new "ASP.NET MVC 2 Empty Web Application" and everything then worked accoring to the instructions (with the exception of the System.ServiceModel.Activation reference).

JohnO42 Jan 27, 2011 at 1:42 PM 
When I create and build this project in VS2010 I get the error "System.Web.Routing.RouteCollection does not contain a definition for 'AddServiceRoute'" however when I load the sample application ContactManager, it builds without error. What am I missing?

Also, you say to reference System.ServiceModel.Web.Activation - however I believe it's System.ServiceModel.Activation.

Thanks! John