How to create REST/POX web services with WCF

Posted by adamjh on Nov 6th, 2007

After a horribly unfulfilling day of hacking at .Net, Perl, and Ruby SOAP implementations... trying to get them to talk nicely to each other... I went to sleep last night with the realization that attempting to achieve interoperability through SOAP would be a never-ending war.

So, I woke up this morning with the desire to make some of our .Net web services RESTful.  One of the great things about Windows Communication Foundation (WCF), the subset of the .Net Framework that provides web service capabilities, is the ability to switch between SOAP/REST and POX/JSON configurations without changing most of your underlying code.

Unfortunately, with .Net 3.5 and Visual Studio 2008 still in beta (for at least a few more weeks anyway), I couldn't find any good documentation/tutorials/howtos on how to do this.  So, after a lot of trial and error, here are the steps to successfully create a RESTful web service with Plain Old XML endpoints, starting with the sample WCF Service Application template that ships with Visual Studio:

1. Create a new WCF Service Application

In Visual Studio, create a new Visual C# project using the "WCF Service Application" template.

2. Add a RESTful service endpoint

In your application's configuration file (Web.config or App.config), add the following endpointBehaviors section right above the existing serviceBehaviors section.  It should now look something like this:

    <behaviors>
      <
endpointBehaviors>
        <
behavior name="webBehavior">
          <
webHttp />
        </
behavior>
      </
endpointBehaviors>
      <
serviceBehaviors>

Now add the following "rest" endpoint to your existing service section so that it looks like:

      <service name="RESTService.Service1" behaviorConfiguration="RESTService.Service1Behavior">
        <!--
 Service Endpoints -->
        <
endpoint address="" binding="wsHttpBinding" contract="RESTService.IService1"/>
        <
endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <
endpoint address="rest" behaviorConfiguration="webBehavior" binding="webHttpBinding"
         bindingConfiguration="" contract="RESTService.IService1" />
      </
service>

3. Reference System.ServiceModel.Web 

Add a reference to the .Net System.ServiceModel.Web assembly.  You can do this by going to Project->Add Reference, and selecting "System.ServiceModel.Web" from the .NET tab.

At the top of your service interface file (i.e. IService1.cs), add:

using System.ServiceModel.Web;

4. Add a WebGet attribute

The default sample GetData() method in your service interface file should look like:

        [OperationContract]
        string GetData(int intParam);

We'll make this RESTful and accessible through HTTP GET by adding a WebGet attribute:

        [OperationContractWebGet]
        string GetData(int intParam);

Testing it out

At this point, you should be able to build and run your program, and access your new RESTful web service at the following URL:

http://localhost:[port]/Service1.svc/rest/GetData?intParam=1337 

You should get the following output:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">You entered: 1337</string>

Note: [port] will be chosen at random when you build and run your program from within Visual Studio.  When you run for the first time, you will see a notification with the port in the system tray.  You can also hover over the ASP.NET Development Server icon in the system tray at any time to find the port number.

Using HTTP POST and URI Templates

If you want to submit information to your service using HTTP POST or another HTTP method, simply replace the WebGet attribute with the WebInvoke attribute, whichdefaults to POST and has an optional Method parameter (for PUT, DELETE, and other less common methods).

If you want to use a different URI scheme, WCF makes it really easy to do so.  For example, try:

        [OperationContractWebGet(UriTemplate = "data/{intParam}")]
        string GetData(string intParam);

And now try accessing your service at:

http://localhost:[port]/Service1.svc/rest/data/5 

Notes: We had to change the intParam from type int to type string, because URI Templates expect string parameters.  Inside of the GetData() method, we could convert the parameter back to an int with a simple call to int.Parse(intParam).  It's also possible to clean up the "Service1.svc" and "rest" URI sections by changing the service host and endpoint addresses.

Hope this helps anyone out there trying to get started creating a simple REST/POX web service with WCF.  This should be significantly better documented in the near future as Visual Studio 2008 RTMs.  At that point, some of the snippets above may need to change slightly depending on any changes that have been made to the framework or the sample applications since Beta 2 -- if you notice any issues or find this useful, please post a comment!

Also, for a lot more background on web services in .Net, check out Steve Maine's blog.  I saw him speak earlier this year at MIX, and he and his team are doing some really great work at Microsoft in this area.

How to consume a WCF service from Perl with SOAP::Lite

Posted by adamjh on Jul 23rd, 2007

Due to the outdated state of Perl's only SOAP library and less-than-stellar documentation on Windows Communication Foundation web service interoperability, getting a Perl script to consume a WCF service sent me on a debugging adventure accompanied by a scavenger hunt for information scattered across the web.

Below are the tweaks that must be made to a new WCF service created using the "WCF Service Library" project template in Visual Studio 2008 Beta 1 ("Orcas") and an example of a how to call the service from a SOAP::Lite client script:

Step 1. Change the service endpoint binding from the default wsHttpBinding to basicHttpBinding:

    <endpoint address ="" binding="basicHttpBinding" contract="Service1.IService1" />

Step 2. Change the data contract format to RPC:

    [ServiceContract]
    [DataContractFormat(Style=OperationFormatStyle.Rpc)]
    public interface IService1
    {

Step 3. Specify an on_action() method in the SOAP::Lite client to override the default Namespace#Action with the format WCF expects:

$data = SOAP::Lite
  -> uri('http://tempuri.org/')
  -> proxy('http://localhost:8080/IService1')
  -> on_action(sub{sprintf '%sIService1/%s', @_})
  -> GetData(SOAP::Data->name('intParam' => 5))->result;

Note: If you decide to do this, you should understand the implications of changing the service endpoint binding and the data contract format.  Supporting information is available somewhere in the bowels of MSDN.

Update [Nov 5 2007]: I ran into new problems when moving from SOAP::Lite 0.55 (the highest supported in ActivePerl on Windows) to SOAP::Lite 0.69 (the latest version as of now, and running on Linux).  It seems SOAP::Lite evolved from the SOAP 1999 (1.1) to 2001 (1.2) schema, and somewhere in the mix, new conflicts arose with WCF interoperability.  After a few hours of horrid tracing and hacking, I've decided to ditch Perl and SOAP altogether for Ruby and REST.  Welcome, Adam, to the year 2007.