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: https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
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
Anonymous
August 22, 2007
The comment has been removedAnonymous
August 25, 2007
Link Listing - August 25, 2007Anonymous
September 07, 2007
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.Anonymous
February 06, 2008
The comment has been removedAnonymous
April 03, 2008
My buddy Justin wrote about how to set the Content-Type headers in a WebGet method in a WCF REST app.