Saturday, January 29, 2011

WCF REST service with custom http header check in .NET 4

This is the posting I initially intended to write when I started writing WCF REST and .NET 4.0.

This posting outlines how to make a simple http header check in the WCF REST based service and depending on the the outcome of the header evaluation either return the result or throw an WebFaultException.

This WCF service is built using .NET 4.0 only without using the WCF REST starter kit (see more information here REST in Windows Communication Foundation (WCF) and here WCF REST Starter Kit Preview 2.

Start out by making a new project in Visual Studio, choose "Online Template" and select the "WCF" sub category. Select "WCF REST Service Template 40".

Change the code of the Service1.cs file to look like the following.

using System.Net;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;

namespace WcfRestService1
 // Start the service and browse to http://<machine_name>:<port>/Service1/help to view the service's generated help page
 // NOTE: By default, a new instance of the service is created for each call; change the InstanceContextMode to Single if you want
 // a single instance of the service to process all calls. 
 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
 public class Service1
  [WebGet(UriTemplate = "{id}")]
  public List<SampleItem> GetProductById(string id)
   if (WebOperationContext.Current.IncomingRequest.Headers["MyCustomHttpHeader"] == null) 
    throw new WebFaultException<string>("The custom httpheader 'MyCustomHttpHeader' has not been set.", HttpStatusCode.BadRequest);
   return new List<SampleItem>() { new SampleItem() { Id = 1, StringValue = "Product1" } };

Build the solution and try to access the url http://localhost:some_random_dev_web_server_port/Service1/GetProductById?id=1

This was kind of expected, but notice how neat this is tying in with the http request return codes.

If we look at this in Fiddler we will see the following.

As expected according to our code in the service 

if (WebOperationContext.Current.IncomingRequest.Headers["MyCustomHttpHeader"] == null) 
                throw new WebFaultException<string>("The custom httpheader 'MyCustomHttpHeader' has not been set.", HttpStatusCode.BadRequest);

If we now use the Request Builder in Fiddler and add the custom http header "MyCustomHttpHeader" we will see the following result in Fiddler.

If you want to let headers flow back and forth between clients and the services your best option is to add some new classes implementing the interfaces IClientMessageInspector, IEndpointBehavior and if you want this to be configurable from the .config file you need to extend the base class BehaviorExtensionElement.

You can see a sample implementation here WCF REST client using custom http headers

WCF REST and .NET 4.0

REST  and SOAP have long been available as specifications how to access and interact with services published on the internet (or intra- /extra- net). Yahoo, Google and Amazon Web Services have long been using REST as the primary way to expose different APIs. In the .NET world we initially had SOAP based web service support built into Visual Studio (.NET / 2003 / 2005), meaning that we could point Visual Studio to a WSDL file and generate the needed code to interact with this service. You could use a REST based web service using the .NET framework by manually using a combination of HttpWebRequest, HttpWebResponse and generating supporting classes for the returned XML using xsd.exe, but there was no built in support for REST based services in the IDE.

With the revealing of the new API codenamed "Indigo" the implementation of the WS* standards into an easy and coherent programming model, as well as incorporating consuming any service no matter where it was located (In process, webservice ... ) using the same programming model, WCF was born and released with .NET 3.0.

In the WCF programming model it does not matter where the service is located. The same unchanged client code can communicate with a service located in the same app domain, across app domains but in the same process, or inter process on the same machine. The same client code can also consume and use a services on different machine either on a LAN or across the inter-, intra-, extra- net.

Juval Löwy has a great note about this in his book Programming WCF Services.

Conceptually, even in C# or VB, there are endpoints: the address is the memory address of the type’s virtual table, the binding is CLR, and the contract is the interface itself. Because in classic .NET programming you never deal with addresses or bindings, you take them for granted, and you’ve probably gotten used to equating in your mind’s eye the interface (which is merely a programming construct) with all that it takes to interface with an object. The WCF endpoint is a true interface because it contains all the information required to interface with the object. In WCF, the address and the binding are not preordained and you must specify them.
Obviously due to the physical differences in how the messages are transported from client to service there are circumstances that need to taken into account. A slow WCF service located across the world, should limit the round trips as much as possible and make sure that the OperationContract is not a "chatty one". Funny enough this applies equally well for the service located in the same app domain in the same process but for a different reason. In the remote scenario it is due to performance, in the same app domain the reason is to achieve an location agnostic service, which can be moved to a remote location only by changing the endpoint  in the configuration file. This is not enforced by the framework but is good programming practices.

Now with .NET 4.0 we have built in support for calling and consuming REST based web service. However especially if you rely on http headers to transfer custom meta information to the service you will have to dive into the extensibility points of WCF. Initially this posting was supposed to be concerning that subject specifically but seeing how it ended up being more of a history lesson of WCF, I have posted that as a separate post which is located here WCF REST service with custom http header check in .NET 4