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




11/03/2009 at 11:53
Thanks a lot! That’s exactly what I have been desperately looking for!
Thank you for sharing your knowledge, you saved my time.
Regards,
Vladimir
13/03/2009 at 09:18
Glad I could help ;-)
24/03/2009 at 10:20
Great article!
10/06/2009 at 07:33
Excellent article. Looked number of places for this information.
Thanks.
08/07/2009 at 20:43
Thanks, I appreciate your feedback.
06/05/2010 at 19:20
[...] it’s just not good. If you want to read specifically about managing cookies using inspectors this is the post that got me [...]
04/04/2011 at 18:38
In windows phone 7 there is no support for IClientMessageInspector.
Is there easy way to extend CookieManagerMessageInspector to support cookies management in window phone 7?
13/07/2011 at 09:02
@Gary The only extensibility point available for WCF in Windows Phone 7 is custom bindings. This approach offers the greatest degree of control over the entire messaging pipeline, but is also the most complex. Luckily there’s a great blog post that describes how to write your own message inspector in a custom binding: http://blogs.msdn.com/b/carlosfigueira/archive/2011/06/21/wcf-extensibility-extensibility-in-windows-phone-and-silverlight-3.aspx
08/06/2011 at 16:37
Thank you, this solved my problem. Surprisingly, I couldn’t find anything on the web that directly addressed this topic except this page.
10/06/2011 at 21:12
@steven Glad I could help :)
13/07/2011 at 01:46
fantastic article. nicely formatted, great flow, and clean concise code samples.
13/07/2011 at 07:36
Thanks, I really appreciate your feedback.
26/10/2011 at 08:48
Great article! Unlike other ones, it contains all the information needed in one place in a well structured manner.
15/03/2012 at 16:04
Hi
We have an XBAP client application that communicates via WCF services to an IIS server within the internal network. We want to internet face the application through a reverse proxy (Netware Access Manager). These are the steps.
1) User logs into the reverse proxy server with valid username/password credentials.
2) A session cookie in IE is created for the reverse proxy.
3) They download the XBAP application and run it.
4) The WCF client service calls are blocked by the Reverse proxy as they do not have a valid session cookie to pass through the portal.
My question… is it possible to use the Internet Explorer reverse proxy session cookie cached on the client and add it to the http response header for the WCF calls so they can pass through the reverse proxy?
Would that work?
27/03/2012 at 09:43
Hi Gary,
Unfortunately, the short answer is no, the XBAP application won’t be able to retrieve the proxy session cookie created by the browser.
The reason is that XBAP applications are only able to access session cookies that originate from a requests made by the application itself. Session cookies created by the browser are out of scope. This is due to the fact that browser hosted WPF applications run outside the browser in a separate process (PresentationHost.exe), which of course can’t peek into the browser’s memory space.
However, an XBAP application can access persistent cookies stored in the browser’s cache using the Application.GetCookie method. A possible workaround then could be to persist the proxy session cookies in cache and access them from the XBAP app using
Application.GetCookie(new Uri("http://proxyserver")).24/04/2012 at 14:57
Hi Enrico
Thanks a lot…You information was most helpful to us. The reverse proxy was stripping out the session cookie before reaching the XBAP deployment/services web server as well so we had some fun there.
The solution was to capture the reverse proxy authentication cookie on the client in javascript, pass it to the server in querystring values (forms could easily be used), then on the server recreate the cookie as a persistent cookie (with a short lifespan) from the querystring values, this new cookie is then sent to the client (auth cookies were only stripped out of requests but not responses), it is then stored on the client in the cookie cache on disk, we redirect from the client to the XBap, PresentationHost is started and it successfully reads the authentication cookie from disk. This means that the file download requests from PresentationHost for the application Manifest and subsequent download requests for the Application files all contain the authentication cookie and are therefore allowed through the reverse proxy and are successful. We then remove the persistent cookie from within the XBAP application and re-create it as a session cookie so it’s removed when the browser is closed. We then include the new session cookie for WCF communication.
Gary
21/05/2012 at 19:25
@Gary I’m glad you worked it out :)
18/06/2012 at 09:22
Very helpful, thankyou
25/06/2012 at 11:25
[...] Managing shared cookies in WCF Share this:ShareTwitterLinkedInDiggFacebookPrintRedditStumbleUponEmailLike this:LikeBe the first to like this. [...]
25/06/2012 at 11:27
[...] Managing shared cookies in WCF [...]
15/08/2012 at 19:34
So, I needed to reuse an auth cookie between multiple requests. I just added this
http://stackoverflow.com/a/6157613/576446
and now I can pass my cookie string into the inspector for each request. Thanks!
15/02/2013 at 10:19
Haven’t tested just yet but must say it is written in a fluent and highly understandable manner. Very helpful, thanks!