Tuesday, 27 March 2012

ASP.NET Web API Series - Part 0: Why not WCF Web API?

[Level C3]

I am starting out a series on ASP.NET Web API. This will start look into features of the beta version that was released in the last few weeks.

But before that, we start with a journey into the history and stages of this framework as it has had quite a few changes in the direction.

Birth of WCF

I remember my enthusiasm with remoting when it came out. I personally preferred it to Web Services and as it turned out, it provided a more seamless transport of DTOs (Data Transfer Objects).

Remoting was superceded with  WCF. When WCF, WPF and WF was announced with .NET 3.0, as a middleware specialist, I naturally picked up WCF to learn. I was amazed with the power and flexibility of design - yet it was extensible. So the world was perfect wasn't it?

Well we later found that, no it was not. So what was the problem?

The fallacy was that WCF at its heart was nothing more than an RPC framework. (details coming!)

Let's remember RPC frameworks were not new. Microsoft had DCOM which later was boosted to COM+. But what they lacked was the interoperability. When XML gained popularity some quickly picked up that XML can solve the interoperability issues of COM+ and SOAP was born. This lead to the development of SOAP web services but we soon realised that we need something bigger and more flexible than ASMX web services to be able to support all the new shiny WS-* standards.

And in the middle of 2000s, we got the WCF. It was built on the top of WSDL goodness (hence interoperable with existing Web Service clients) while abstracting pretty much everything else (transport, synchronicity, one-way or two-way or duplex, ...)

As an RPC framework, WCF sacrifices context of the transport for the seamless marshalling of DTO/payload according to the operation contract. So it is Transport-Agnostic and in that respect, WCF is beautiful or in fact beauteous.

Let's have a look at a typical service operation.

[ServiceContract]
public interface IWidgetService
{
    [OperationContract]
    string GetDescription(int id);
}
This is a typical service interface. GetDescription is is a typical service operation. There is no magic involved here, but according to WCF abstractions, the logical operation has been completely abstracted from the transport being used. You could be using MSMQ, HTTP, TCP, etc to achieve this operation. Microsoft have not implemented FedExBinding (!) but theoretically this message could be transported physically using FedEx/snail mail - perhaps I am taking the abstraction a bot too far. So I could swap the HTTP binding with TCP binding without changing a line in my code, all in the configuration files.

Fallacy of WCF


Now here is a challenge. What if I need to specify anything specific to the transport in the runtime? Microsoft's answer has been you actually do not need to because we did not design it as such! This post from 2007 clearly explains it:
Can I get the IP address of a client connecting to my service? 
No. Sorry. In most cases this information is not available. Exposing such functionality is left to the transport to be done in an implementation-specific manner. The most popular transports we supply out of the box do not offer this. ..
Now, this other post from 2006 expects you to expose such information as headers. It is true that this would not change the service interface, but it would clearly change the WSDL.

Now it is history that Microsoft finally gave in and implemented such features - perhaps reluctantly. But it was clear that the community was not impressed by the lack of support for getting such information (one in the first post pointed out "this is basic stuff"). Solution was to use Thread's storage area to store the metadata as message properties:

[ServiceContract]
OperationContext context = OperationContext.Current;
MessageProperties prop = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpoint =
    prop[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
string ip = endpoint.Address;

So OperationContext.Current very much like HttpContext.Current became the curse of the gnosis of Transport-Agnosticism - if there is such sentence in the English language!

Now using OperationContext.Current per se is not a huge problem especially if it is done sparingly. Reality is a lot of day-to-day RPC operations, would not need to access message properties. So, perhaps life was good enough again and WCF started to be implemented in the enterprise.

Popularity of REST and birth of WCF REST

It is true that life was good again but the industry - especially leaner startup companies - started to re-discover and embrace HTTP. While SOAP reduced HTTP to mere a transport mechanism, REST enthusiasts started to talk about media types, hyperlinks, custom verbs, etc.

Ironically, one of the main features associated with REST (yet having little to do with it) was clean URLs that became hallmark of REST. Since Mircosoft had already started to work on cleaner routing for ASP.NET MVC and supporting alternate HTTP verbs (such as PUT and DELETE) was there, this feature was almost readily available so associating WCF with REST seems like a good idea.

In reality, WCF REST had the same shortcomings of conventional WCF. This fundamental fact cannot be hidden that WCF was designed as a Transport-Agnostic framework and it was impossible to introduce HTTP semantics without complete redesign and losing the Transport-Agnosticity. Hence Microsoft decided to continue enriching WCF with more WS-* standards (e.f. federation) for the enterprise while creating a different system for RESTful HTTP.

WCF and REST?

Reality is marriage of WCF anbd REST was flawed right from the start. WCF is an RPC implementation and as such works based on IDL. WCF uses WSDL as an implementation of IDL, a hangover from the days of Web Services.

I am not trying knock WCF. True, WCF is an RPC implementation, but to my knowledge it is the best one. I think WCF still rocks in the enterprise where services have to comply with reams and reams of in-house rules and regulations - and all interfaces have to be cast in the stone. If all you care is RPC, WCF is your best friend.

Reality is Web 2.0/Cloud/New Web/WhateverYouCallIt outdated all Microsoft Innovations of mid-2000 soon after they came out. On the UI front, WPF and Silverlight succumbed to the popularity of iPad (yes perhaps Steve Jobs did kill Silverlight by banning it from iPad) and HTML5 bandwagon. Simplicity of lean RESTful Web APIs overshadowed WCF. And perhaps WF killed itself by its poor performance, it had no chance of survival when compared to shiny Service Bus implementations out there (namely NServiceBus).

To summaries, WCF and REST belong to two completely different philosophies. While RPC (hence WCF) relies on stringent interface definition, REST embraces discovery of possibilities through hypermedia and content negotiation. RPC restricts change while REST assumes intelligent clients able to react to changes. WCF relies on careful interface definition through WSDL while RESTful HTTP only provides OPTIONS verb to define high level of what is possible. As such, I for one believe RESTful WCF is just an oxymoron!

If you have to choose between REST and WCF, here are a few things you need to consider:

  1. Ease of client coding: WCF client code can be auto-generated by using the WSDL. On the other hand, REST has a client burden in such a way that REST client have to fully understand and respect HTTP  (WCF: 1 - REST: 0)
  2. Client device support: This is where REST shines. You can invoke REST from your browser using Javascript.  (WCF: 0 - REST: 1)
  3. WS* Support: WCF has done a lot of work to fully support WS* protocols. In an enterprise, this can be imporant  (WCF: 1 - REST: 0)
  4. Federated security (OAuth, OpenID, etc): REST and WCF both support them although REST is more aligned for it (WCF: 1 - REST: 1)
  5. Better decoupled implementation: REST scores much higher on that as long as both client and server respect HTTP  (WCF: 0 - REST: 1)
  6. Better use of HTTP features (such as caching): REST scores so much higher. WCF/SOAP always uses POST which is neither Idempotent nor safe while this can be implemented in REST using all varieties of verbs.  (WCF: 0 - REST: 1) 
  7. Supporting various formats: REST can implement content negotiation while WCF mainly uses XML  (WCF: 0 - REST: 1)
One-liner: For a new API, I would definitely choose Web API. For an existing WCF implementation, I would not immediately jump to migrate to Web API. In enterprise, WCF might in fact be a more suitable option.


WCF Web API

Microsoft put Glenn Block, the MEF dealer, in charge of a new project to turn WCF REST into something sensible. As Glenn himself clarified, WCF Web API was an HTTP-friendly (rather than claiming to be RESTful) implementation exposing a lot of the HTTP goodness with little compromise.

One of the main changes was ability to define RPC interfaces as HttpRequest<T> and HttpResponse<T>, allowing transport specific context of HTTP to be accessible within the method.

Now the reason that WCF Web API was later renamed into ASP.NET Web API was perhaps more to do with the political milieu of the Microsoft at the time where WCF teams were integrated into ASP.NET team. As we will later see, a journey that started with WCF REST with WCF gradually moving towards ASP.NET MVC, it has been almost complete now with the new Web API sharing not only routing and HTTP verb definition, but also concepts such as controller. They are so similar that one wonders why on earth we have to have both.

5 comments:

  1. nice article....

    Regards
    Vivek

    ReplyDelete
  2. Very informative comparison. I never liked WCF, mostly due to configuration problems when trying to do many things at once - SOAP, JSON, WinAuth... (I often ended up reverting to ASMX) but your article may change my mind a bit.

    MEF Dealer... Good one :-)

    ReplyDelete
    Replies
    1. Pleased to hear you found it useful.

      With regard to "MEF Dealer", it is on Glenn's twitter account bio!

      Delete
  3. Very good post. I always wondered how could I explain better the reasoning behind choosing wcf or web api. Now I have the answer.
    Thank you :)

    ReplyDelete