One does not simply… switch to WCF
In my last blog post, I talked about the nature of new code, and how it sometimes spawned a spontaneous redesign of existing architecture to avoid future technical debt. In my case, laying the initial foundation for mobile and tablet apps caused me to rethink my web service layer. Since then, I’ve been spending a lot of time going through the KitchenPC API and making sure everything is solid, well designed, consistent and flexible. After all, once mobile and tablet apps have been built, it will be difficult to change the interface contracts.
Unfortunately, I seem to have fallen down a rabbit hole and signed up for a pretty extensive re-design of the KitchenPC back-end. I ran into conflicts between my ideal API design and the limitations of ASP.NET Web Services. In the end, I decided to upgrade the KitchenPC web service layer to use a more modern framework, Windows Communication Foundation (WCF).
Turns out, one does not simply… switch to WCF.
The fact that an ASP.NET Web Service extends a common base class, WebService, and a WCF Service does not, is an important consideration when porting existing code. Any methods that depend on the ASP.NET request pipeline, such as references to Context, Session, or Application, will need to be reconsidered. This means you cannot depend on things like cookies, HTTP headers, IP addresses, identity management, and other things users of the ASP.NET framework take for granted.
To understand why, let’s take a step back and look at the design behind WCF. WCF was implemented as a protocol agnostic communications framework. Nowhere does WCF assume that HTTP is being used as a transport mechanism over the wire. One could be using raw TCP/IP, or perhaps named pipes, shared memory, or a USB controlled carrier pigeon launcher. Nowhere does WCF assume it’s even running on a web server like IIS. A WCF endpoint could be running within a console application, or a Windows Service. Many of these architectures have no concept of things like HTTP headers, session state management or other things associated with the web world. Though a pigeon could probably carry a cookie if it were only a few bites.
For this reason, within the context of a WCF operation, you’re working with very generalized notions of communication. I was definitely bitten by this “limitation” while porting my web services over, as I use session cookies to communicate authentication information used for user specific service calls.
Those who want to quickly port their web services over to WCF will, however, be pleased to know that the designers of WCF foresaw this radical paradigm shift and took pity. There exists a compatibility mode that bridges the ASP.NET pipeline with WCF, and permits information sharing between those two very different worlds. This compatibility mode can be enabled in your web.config file by using:
<system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" ... /> </system.serviceModel>
When running in this mode, you’ll be able to access things such as HttpContext.Current and session state. If you’re interested in how this works under the covers, there’s a great blog post here. This is most definitely an approach for those building services that never need to run outside the context of a web server or support protocols other than HTTP. However, I decided to really dive into the WCF world and design a fully independent KitchenPC API and not take the easy way out. Either that, or the fact that I couldn’t get ASP.NET compatibility working under IIS when running in Integrated Pipeline mode and I got frustrated. But let’s go with the first thing, it sounds more noble.
Luckily, getting rid of cookie dependencies was fairly straight forward. My web services already took a ticket string which contained a serialized authentication ticket. However, this parameter was optional if the HTTP header had a cookie value set containing the same information, as I didn’t want to pass in that potentially long ticket twice in each HTTP request. The ticket was also never returned back with the Logon web method, since it just set the cookie in the HTTP response. The new design requires a session ticket to be supplied on sensitive web service calls, and it’s up to the client to store that ticket for future calls. In my mind, this is simpler and more straight forward. Web, mobile and tablet will all call the API in the same way, and enforcing these parameters becomes less complicated in terms of code.
You might be asking me, at this point, what the actual benefit of switching to WCF is. After all, the web services worked just fine before, right? Do I really need a protocol agnostic KitchenPC service, when in reality HTTP will be the primary, if not only, means of access? Well, the answer is flexibility. Massive amounts of flexibility. Every single last component of WCF is fully customizable or replaceable, from message inspection, to fault handling, to serialization. Don’t like something about how your service works? Change it. And that’s where WCF starts to get extremely complicated, as I’ve been learning over the past few days. That’s also why I’ve decided to write a couple more WCF posts, summarizing how I’ve tweaked WCF to build the KitchenPC web service I’ve always wanted.