Managing shared cookies in WCF
06/02/2009
Managing state across the HTTP protocol has always been one of the major challenges faced by developers when building applications on the web. Of course web services are no exception.
One way to overcome the stateless nature of HTTP without putting to much load on the web server, is to offload some of the information that has to be saved in the context of a particular conversation over to the client. The HTTP specification provides a native mechanism to do just that, by allowing web servers to bundle small pieces of textual data in a dedicated header of the response messages sent to the clients. These recognize the special payload, extract it, and store it in a local cache on disk to have it ready to be sent with every subsequent request. These small texts are technically known as “cookies”.
Cookies are opaque in ASMX
Cookies go back a long time in the history of HTTP, and have served the Internet (fairly) well so far. Sure they brought some serious security issues with them, but for the most part they have been a conventient way for developers of web sites/web applications to save temporary pieces of information off the server and have it transparently sent back by the client with each request.
This guarantee comes from the fact
that every web browser on Earth has had the notion of cookies since web browser have had built-in support for cookies for the last 15 years or so.
However, when it comes to web services, this assumption is no longer valid, since the client isn’t necessarily a web browser and doesn’t have to know how to handle cookies.
In the ASMX programming model, this problem has a quite simple solution. The client objects used to invoke operations on a web service can optionally reference an instance of a “cookie container”, were all cookies passed back by the web server are automatically stored and sent with each request.
using System.Net; public class Program { private static void Main(string[] args) { // Creates a new instance of a client proxy for an ASMX Web service MyWebServiceClient client = new MyWebServiceClient(); // Creates the cookie container and assigns it to the proxy CookieContainer cookieJar = new CookieContainer(); client.CookieContainer = cookieJar; // From now on cookies returned by any of the web service operations // are automatically handled by the proxy client.DoSomething(); } }
The advantage with this approach is that it is fairly opaque to the developer, which can inspect the contents of the cookie container at any time. As a bonus, it allows the same cookie container to easily be shared between multiple clients, enabling the scenarios when same cookie is required by multiple web services.
But they are transparent in WCF
In the WCF world, things are a little bit different. WCF, being a transport-agnostic technology, doesn’t allow the concept of a cookie to be directly reflected in the high level API, since it is specific to the HTTP protocol. This translate in practice in the web service client objects not having any CookieContainer property to set and retrieve.
However this isn’t necessarily a problem, since Microsoft did put a the possibility to enable automatic “behind the scenes” cookie management for HTTP clients. This of course is implemented at the WCF binding level, and can be switched on with a configuration setting:
<system.ServiceModel> <bindings> <basicHttpBinding allowCookies="true"> </bindings> <client> <endpoint address="http://localhost/myservice" binding="basicHttpBinding" contract="IMyService" /> </client> </system.ServiceModel>
When this option is enabled the client will make sure all cookies received from a given web service are stored and properly sent on each subsequent request in a transparent fashion. But there is a catch: the cookie is only handled in the conversation with one web service. What if you need to send the same cookies to different web services?
Well, you’ll have to explicitly set the EnableCookies setting to false (kind of counter-intuitive I know, but required nonetheless) and start managing the cookies yourself. Luckily, there are a couple of solutions.
Ad-hoc cookie management
If you wish to manually retrieve, store and send a the same given set of cookies from two different web service client objects in WCF, you could do this ad-hoc this way:
using System.ServiceModel; using System.ServiceModel.Channels; public class Program { private static void Main(object[] args) { string sharedCookie; MyWebServiceClient client = new MyWebServiceClient(); using (new OperationContextScope(client.InnerChannel)) { client.DoSomething(); // Extract the cookie embedded in the received web service response // and stores it locally HttpResponseMessageProperty response = (HttpResponseMessageProperty) OperationContext.Current.IncomingMessageProperties[ HttpResponseMessageProperty.Name]; sharedCookie = response.Headers["Set-Cookie"]; } MyOtherWebServiceClient otherClient = new MyOtherWebServiceClient(); using (new OperationContextScope(otherClient.InnerChannel)) { // Embeds the extracted cookie in the next web service request // Note that we manually have to create the request object since // since it doesn't exist yet at this stage HttpRequestMessageProperty request = new HttpRequestMessageProperty(); request.Headers["Cookie"] = sharedCookie; OperationContext.Current.OutgoingMessageProperties[ HttpRequestMessageProperty.Name] = request; otherClient.DoSomethingElse(); } } }
Centralized cookie management
In situations were cookies must be managed in the same way for all web services invoked from a client applications, your best bet is to opt for a centralized solution by applying a very useful feature in WCF: message inspectors.
Message inspectors provide a hook in the WCF messaging pipeline offering the chance to look at and possibly modify all incoming or outgoing messages that transit on the server-side as well as on the client-side. The inspectors that are registered with the WCF runtime receive the messages before they are passed on to the application or sent to the wire, depending on whether it is an incoming or outgoing message.

This way, it is possible to catch all HTTP responses coming from the web server, extract any cookies contained within the messages, and manually inject them in all subsequent HTTP requests on their way out. Here is a simplified view of the solution:
using System.ServiceModel; using System.ServiceModel.Channels; public class CookieManagerMessageInspector : IClientMessageInspector { private string sharedCookie; public void AfterReceiveReply(ref Message reply, object correlationState) { HttpResponseMessageProperty httpResponse = reply.Properties[HttpResponseMessageProperty.Name] as HttpResponseMessageProperty; if (httpResponse != null) { string cookie = httpResponse.Headers[HttpResponseHeader.SetCookie]; if (!string.IsNullOrEmpty(cookie)) { this.sharedCookie = cookie; } } } public object BeforeSendRequest(ref Message request, IClientChannel channel) { HttpRequestMessageProperty httpRequest; // The HTTP request object is made available in the outgoing message only // when the Visual Studio Debugger is attacched to the running process if (!request.Properties.ContainsKey(HttpRequestMessageProperty.Name)) { request.Properties.Add(HttpRequestMessageProperty.Name, new HttpRequestMessageProperty()); } httpRequest = (HttpRequestMessageProperty) request.Properties[HttpRequestMessageProperty.Name]; httpRequest.Headers.Add(HttpRequestHeader.Cookie, this.sharedCookie); return null; } }
Message inspectors are enabled through the WCF extensibility mechanism called behaviors for single web service operations, entire web service contracts, or even specific endpoint URLs, depending on the scope the will operate in.
Here you can download a sample application showing how to implement a client-side message inspector to share the same cookies across multiple web services.
Download WCF Cookie Manager
/Enrico
Migrating ASP.NET Web Services to WCF
27/11/2008
I am currently in the middle of a project where we are migrating a (large) amount of web services built on top of ASP.NET in .NET 2.0 (commonly referred to as ASMX Web Services) over to the Windows Communication Foundation (WCF) platform available in .NET 3.0.
The primary reason we want to do that, is because we would like to take advantage of the binary message serialization support available in WCF to speed
up communication between the services and their clients. This same technique was possible in earlier versions of the .NET Framework thanks to a technology called Remoting, which is now superceded by WCF. In both cases it requires that both the client and server run on .NET in order to work. But I digress.
Since the ASMX model has been for a long time the primary Microsoft technology for building web services on the .NET platform, I figured they must have laid out a nice migration path to bring all those web services to the new world of WCF. It turned out, they did!
The quick way
If you built your ASMX web services with code separation (that is, all programming logic resided in a separate code-behind file instead of being embedded in the ASMX file) it is possible to get an ASMX web service up and running in WCF pretty quickly by going through a few easy steps:
- Your WCF web service class no longer inherits from
the System.Web.Services.WebService class so remove it. - Change the System.Web.Services.WebService attribute on the web service class to the System.ServiceModel.ServiceContract attribute.
- Change the System.Web.Services.WebMethod attribute on each web service method to the System.ServiceModel.OperationContract attribute.
- Substitute the .ASMX file with a new .SVC file with the following header:
<% @ServiceHost Service="MyNamespace.MyService" %>
- Modify the application configuration file to create a WCF endpoint that clients will use to send their requests to:
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="MetadataEnabled"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="MyNamespace.MyService" behaviorConfiguration="MetadataEnabled"> <endpoint name="HttpEndpoint" address="" binding="wsHttpBinding" contract="MyNamespace.IMyService" /> <endpoint name="HttpMetadata" address="contract" binding="mexHttpBinding" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost/myservice" /> </baseAddresses> </host> </service> </services> </system.serviceModel>
- Decorate all classes that are exchanged by the web service methods as parameters or return values with the System.RuntimeSerialization.DataContract attribute to allow them to be serialized on the wire.
- Decorate each field of the data classes with the System.RuntimeSerialization.DataMember attribute to include it in the serialized message.
Here is a summary of the changes you’ll have to make to your ASMX web service:
| Where the change applies | ASMX | WCF |
| Web service class inheritance | WebService | - |
| Web service class attribute | WebServiceAttribute | ServiceContractAttribute |
| Web service method attribute | WebMethodAttribute | OperationContractAttribute |
| Data class attribute | XmlRootAttribute | DataContractAttribute |
| Data class field attribute | XmlElementAttribute | DataMemberAttribute |
| HTTP endpoint resource | .ASMX | .SVC |
As a side note, if you are using .NET 3.5 SP1 the porting process gets a little easier, since WCF will automatically serialize any object that is part of a service interface without the need of any special metadata attached to it. This means you no longer have to decorate the classes and members exposed by a WCF service contract with the DataContract and DataMember attributes.
Important considerations
The simple process I just described works well for relatively simple web services, but in any real-world scenario you will have to take into consideration a few number of aspects:
- WCF services are not bound to the HTTP protocol as ASMX web services are. This means you can host them in any process you like, whether it be a Windows Service or a console application. In other words using Microsoft IIS is no longer a requirement, although it is a valid possibility in many situations.
- Even if WCF services are executed by the ASP.NET worker process when hosted in IIS, they do not participate in the ASP.NET HTTP Pipeline. This means that you have no longer access to the ASP.NET infrastructure services such as HttpContext, HttpSessionState, HttpApplicationState, ASP.NET Authorization and Impersonation in your WCF services.
So what if your ASMX web services are making extensive use of the ASP.NET session store or employ the ASP.NET security model? Is it a show-stopper?
Luckily enough, no. There is a solution to keep all that ASP.NET goodness working in WCF. It is called ASP.NET Compatibility Mode.
Backwards compatibility
Running WCF services with the ASP.NET Compatibility Mode enabled will integrate them in the ASP.NET HTTP Pipeline, which of course means all ASP.NET infrastructure will be back in place and available from WCF at runtime.
You can enable this mighty mode from WCF by following these steps:
- Decorate your web service class with the System.ServiceModel.Activation.AspNetCompatibilityRequirements attribute as following:
[AspNetCompatibilityRequirements(
RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class MyService : IMyService
{
// Service implementation
}
- Add the following setting to the application configuration file:
<system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> </system.serviceModel>
Remember that this will effectively tie the WCF runtime to the HTTP protocol, just like with ASMX web services, which means it becomes prohibited to add any non-HTTP endpoints for your WCF services.
Good luck and please, let me know your feedback!
/Enrico
REST web services
21/11/2008
If you have followed the latest advancements in the technologies and standards around web services, you must have come across the term “REST” at least more than once.
In rough terms REST is a way of building web services by relying
exclusively on the infrastructure of the World Wide Web to define operations and exchange messages. This is an alternative to “traditional” web services, which instead use a set of standardized XML dialects, WSDL and SOAP to achieve the same goals.
The reason I’m writing about REST is that if you, like me, have prematurely judged it as some kind of toy technology, you are in for a real eye-opener!
The history
First of all, let’s be clear about the origin of REST. As a term it means Representational State Transfer, as a concept it stands completely separate from web services.
It was first defined in the year 2000 by a PhD student at the University of California by the name Roy Fielding. Fielding, in his doctoral dissertation entitled Architectural Styles and the Design of Network-based Software Architectures, sought to define the architectural principles that make up the infrastructure of the most successful large-scale distributed system created by mankind: the World Wide Web.
Fielding thought that by studying the Web, he would be able to identify some key design principles that would be beneficial to any kind of distributed application with similar needs of scalability and efficiency. He referred to the result of his research as “REST”.
So, what is REST?
REST is an architectural style for building distributed systems.
The key design principle of a REST-based architecture is that its components use a uniform interface to exchange data.
Uniform interface means that all components expose the same set of operations to interact with one another. In this interface data is referred to as resources and contains three main concepts:
- A naming scheme for globally identifying resources
- A set of operations to manipulate resources
- A format to represent resources
The idea is that generalizing and standardizing the components interface reduces the overall system complexity by making it easier to identify the interactions among different parts of the system.
As of today, the Web is the only system that fully embraces the principle of unified interfaces, and it does it in the following way:
- URI is used as a naming scheme for globally identifying resources
- HTTP verbs define the available operations to manipulate resources
- HTML is the textual format used to represent resources
Applying REST to web services
Now, it is a known fact that the Web was created in order to provide a worldwide network for distributing static documents. However, it has been proven that the Web holds a potential that goes far beyond its original goal. Imagine if we could leverage the REST infrastructure of the Web to build web services. Wouldn’t that be cool?
First of all, let’s take a look at what web services are used for:
- Define a set of operations to manipulate resources
- Uniquely identify these operations so that they can be globally accessed by clients
- Use a common format to represent the resources exchanged between web services and their consumers
Well, the Web seems to have the entire infrastructure we need to accomplish all of those goals already in place. In fact the HTTP protocol defines a pretty rich interface to manipulate data. Moreover this interface maps surprisingly well to the kind of operations usually exposed by web services.
| HTTP verbs | Web Service operations |
| GET | READ |
| PUT | CREATE |
| POST | UPDATE |
| DELETE | DELETE |
Also, web services contracts are inherently accessed through URLs, it isn’t too much of a stretch to use URLs to access single operations in a contract.
Finally, web services encode the contents of their messages using SOAP, which is a XML dialect. But why do we need a whole new protocol to represent resources, when we could simply use XML as is instead?
What we just did, was applying the design principles dictated by REST to web services. The result of this process is commonly referred to as “RESTful” web services.
Wrapping up
This is how REST web services compare to traditional ones:
| Goal of web services | Traditional | REST |
| Identifying resources and operations | SOAP | URL |
| Defining operations | WSDL | HTTP |
| Representing resources | SOAP | XML |
As you can see, REST web services leverage the stability, scalability and reach offered by the same technologies and standards that power the Web today. What’s most fascinating with REST is the huge potential that comes out such a simple design.
However, don’t think even for a moment that REST will ever replace SOAP-based web services. Both architectures have their strengths and weaknesses, and REST is certainly not the right answer for all kinds of applications. I am especially thinking about corporate environments, where the needs for security and reliability are better addressed by the standards incorporated in WSDL and SOAP.
As always, the solution lies in using the right tool for the job.
/Enrico


