Setting HTTP Headers in WCF (.NET 3.5)

One of the cool parts of WCF in the .NET 3.5 is the simplified support of the REST architectural style. URIs, HTTP verbs, and HTTP headers are 1st class citizens in the programming model. Each of these citizens is interesting. I'll focus a bit on HTTP headers here.

HTTP headers dictate a wide array of characteristics of how a server responds to a request and how a client reacts to the response sent by the server. A full discussion is beyond the scope of my blog post, but this stuff has been around for quite a while. You should be able to do a Live Search on HTTP Headers to dig up more info on their uses.

There's two uses that are particularly interesting from a services perspective: Content-Type and Cache-Control.

Content-Type serves as a way for the server to indicate the data format and is expressed as a MIME type label. SOAP / WS-* services generally express data format in terms of schema and WSDL. Schema and WSDL are highly expressive, whereas Content-Type is dramatically simpler. The web tends to rely on Content-Type.

The Cache-Control response header indicates how long a response is valid. It also can include instructions regarding how the client should validate their cache. You can get the particulars straight from the horses mouth:

The easiest way to set the value of these headers in a WCF application is via the WebOperationContext type. An object of this type is normally available in a method of a service object, and follows the usage pattern demonstrated in .NET 3.0's OperationContext type.

Here's how you can set he Content-Type header in a method of a service object (for the HTTP wonks, I've omitted charset):

1 public String SomeMethod(Int32 someNumber) { 2 // normal implementation would go here 3 4 // set the Content-Type 5 WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"; 6 7 // return something 8 return someNumber.ToString(); 9 }

Here's how you could set the Cache-Control response header and the validation HTTP headers:

1 public String SomeMethod(Int32 someNumber) { 2 3 // normal implementation would go here 4 5 // set the Content-Type 6 WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"; 7 8 // call a helper method that sets cache-control header 9 SetCaching(WebOperationContext.Current, DateTime.Now, 120); 10 11 // return something 12 return someNumber.ToString(); 13 } 14 15 private void SetCaching(WebOperationContext context, DateTime lastModifiedDate, Int32 maxCacheAge){ 16 17 // set CacheControl header 18 HttpResponseHeader cacheHeader = HttpResponseHeader.CacheControl; 19 String cacheControlValue = String.Format("max-age={0}, must-revalidate", maxCacheAge); 20 context.OutgoingResponse.Headers.Add(cacheHeader, cacheControlValue); 21 22 // set cache validation 23 context.OutgoingResponse.LastModified = lastModifiedDate; 24 String eTag = context.IncomingRequest.UriTemplateMatch.RequestUri.ToString() + lastModifiedDate.ToString(); 25 context.OutgoingResponse.ETag = eTag; 26 27 }

There are lots of different options available for caching and validation. If there's interest, I will dive into those in a future post. It's hard to gauge what's common knowledge about these headers.

From a debugging perspective, know that Fiddler is your best friend. When you are watching headers on localhost services, you won't see the sessions in Fiddler unless you use the full machine name in the request. The machine name forces the request to go through the fiddler proxy.

Comments (5)
  1. Kevin Daly says:

    One little thing: in Beta 2 there’s a bug in the way LastModifiedDate is handled that causes the LastModified header to be set to an invalid value for HTTP dates (at least in the scenario in which I tried it – see You can get around this by setting the header directly to (per your example) lastModifiedDate.ToUniversalTime().ToString("r") (for example).

    Hopefully this will be fixed for RTM: overall this is very cool – the bit I’ve mentioned is important for conditional get, which is why I’m keen to get it sorted out.

  2. Link Listing – August 25, 2007

  3. Any insight on how System.ServiceModel.Web works would be greatly appreciated.

    After using it since the release of the BizTalk Services Labs, I only discovered today that I can actually return a stream directly!  I had previously been returning a Message that was created from a custom class derived from BodyWriter.  

    I found some details about doing SSL from a blog entry from Gudge but I have still not been able to retrieve client credentials on the server side.

    Like I said, any pointers would be appreciated.

  4. Awnik says:

    HI ,

    I added a reference to System.ServiceModel.Web. and also Imported the System.ServiceModel.Web namespace .

    Imports System.ServiceModel.Web

    But still following line of code shows error

    System.ServiceModel.Web.WebOperationContext.Current.OutgoingResponse.ContentType = "text/html"

    Error 3 ‘Web’ is not a member of ‘ServiceModel’. F:Job_CoretestgroundWCFTestProjectWCFTestProjectWCFTestProjectService1.vb 11 WCFTestProject

    Can you please help

  5. My buddy Justin wrote about how to set the Content-Type headers in a WebGet method in a WCF REST app.

Comments are closed.

Skip to main content