See the entire conversation

A thread about APIs and how/why Service Bus abandoned WCF as primary API in ~late 2010: In the CNCF #CloudEvents project, there's a proposal for "bindings" with the promise that you can have a stable API for sending/receiving events and switch transports/encodings via config ...
31 replies and sub-replies as of Nov 27 2019

My instant reaction: "We've gone there. I understand why you find that attractive. Don't do it." The proposed design, even though seemingly arrived at independently, immediately evokes WCF's service model API + bindings + channel abstraction.
When the original Azure Service Bus team (owning Relays and a lightweight in-memory queue) merged with the durable message broker team (son-of-MSMQ) in 2010, we had to work through a ton of alignment work behind the scenes and at the public API surface.
Priorities were continuity of the existing service experience and tooling alignment. Relay was shipping and none of the new broker was. The Relay's client was just a WCF channel and thus you used WCF to talk to it. (This was before we all saw the light on cross-plat, obviously.)
So one of the ideas was to do the same thing with the broker and make the broker client just a channel and have WCF be the API. You'd choose between brokered/buffered transport and relayed/direct by changing config. (We did indeed build/ship this, find NetMessagingBinding)
The broker folks were vehemently opposed to making this the primary API surface, though. They conceded it might be useful for someone bought into WCF, but insisted that it would severely limit the product options down the road. And they were right, even disregarding cross-plat.
The analysis that resolved the debate was when we jointly took a deep look at WCF's IInputChannel. That's the receiver-side of a one-way message path as you'd use it with a queue or with an event-ingestor partition.
IInputChannel Interface (System.ServiceModel.Channels)
Defines the interface that a channel must implement to receive a message.
docs.microsoft.com
WCF has a handful of these channels that reflect certain patterns, and the rest of the stack, including all the fancy WS-* protocol features and the binding layer to the API, is built on top of those. That is to say, as a channel builder, that's the extent of your toolbox. Finite
The key analysis question was: "How do I call Receive() while passing a filter argument?" - Answer: "You can't."
It was therefore provably impossible for the app-layer to request a specific deferred message - what you do with Receive(sequenceNumber) now - and for that message to be pulled up through the channel stack. WCF's assumptions about Receive() were wrong.
Azure Service Bus message deferral
Defer delivery of Service Bus messages
docs.microsoft.com
Since WCF's channel primitives are effectively not extensible because the whole mountain of the rest of it is built on them and you can't add a method overload to an interface without breaking the world, that one false assumption settled the debate. We built a new API. We had to.
On the HTTP-front, the story was similar. WCF was meant to be the universal communication framework, but for people who wanted to work with HTTP as an app-protocol and not as a mere transport tunnel, the abstractions ended up being far too limiting and WebAPI emerged.
It's superficially attractive to treat all application-layer protocols the same and hide them behind the same API abstraction. That's a mistake. We have those protocol choices because the purposes are different and thus the API is different. /fin
PS: Outside of messaging and eventing, WCF was (and, IMO, still is) a solid framework for RPC-style interactions if you're on Windows/.NET. gRPC isn't all that much different other than being clearly focused on RPC and not having WCF's (strong) XML bias.
I don’t remember WCF supporting streaming or bidirectional streaming. Am I forgetting it or never used it?
It does support streaming. I’ve tunneled live TV streams through WCF for quite a while for a personal solution.
But doesn’t gRPC give you cross plat option as well as more options for payload serialization. Another big one is that it’s becoming hard to find devs who willing or even know WCF which introduces huge maintainability issues.
* “if you’re on Windows/.NET” * WCF let’s you plug the wire encoder; the binary encoder yields a quite compact footprint, especially in session mode, which performs dictionary compression on all metadata. It’s still a good piece of engineering for RPC. You don’t have to use it.
We are using the binary encoder in our app for the past 7 years in production. So one worry is in the next 5 to 10 years how we going to find devs to maintain This WCF app when our current 2 devs move on :)
I enjoyed reading all this history. Thanks for writing this.
I got something for you ;)
I just like the fact that RPC have stood the test of time :) in the early 90s we used homegrown C tools to generate the Stup and Proxies. Then came WS* specs and all the SOAP tools like Apache Axis and Microsoft WCF. And now modern libs like SignalR and gRPC keep it better.
This threads brings back memories. Kudos for trying to stop history from repeating itself.