Windows Communication Foundation (WCF) is The One Way to implement inter-process communication on the .NET platform.  Well, it’s not really the only way, but it’s certainly the most common way.  It’s a bit misused.  Unfortunately, WCF suffers from numerous problems.  It is extremely configuration heavy, it has known design issues, and it has a learning curve that nearly rivals Lisp.  We need a better way to handle inter-process communication in the .NET world.  I’m not proposing a solution in this post, merely throwing out some ideas.  Feedback is welcome in the comments!

What is Windows Communication Foundation?

From MSDN:

Windows Communication Foundation (WCF) is Microsoft’s unified programming model for building service-oriented applications. It enables developers to build secure, reliable, transacted solutions that integrate across platforms and interoperate with existing investments.

Basically, WCF is a highly-configurable API for communication to/from services.  It’s the successor to both ASMX Web Services and .NET Remoting.  It has several advantages over both technologies, not the least of which is the separation of the “contract” from the implementation.  It’s quite useful for building loosely-coupled, standards-compliant end points. 

What’s wrong with it?

Configurability adds complexity, and WCF is very configurable, making it very complex.  There are tools written around managing the app.config entries that it requires.  You can choose to configure WCF via code, but this is not the recommend approach, and it’s still more complicated than it should be.

WCF also suffers from some pretty serious design issues.  For whatever reason, even as we have reached the second major .NET revision since WCF was introduced, the WCF “dispose” semantics remain broken.

The “proxies” themselves are another problem with WCF.  They look exactly like a normal class.  If you hide them behind an interface reference, the fact that you are dealing with a proxy object can be totally obscured, leading to poor implementation choices downstream.  While this is certainly convenient in terms of cranking out code, the drawbacks can be severe.  Imagine how the following will perform if the IDataSource instance is actually a proxy for a remote object instead of a local object. 

public void ListResults(IDataSource source, int count)
    for (int i=0; i < count; i++)
        //This is what we'd call a 'chatty' interface...

In a nutshell, I’d summarize WCF as a tool that tries to solve every problem but only manages to become too complicated to effectively solve much of anything.  It tries to make a complex problem (inter-process communication) simpler by masking it under layer upon layer of abstraction.  This is exactly the same approach that ASP.NET WebForms took.  Does it work some of the time?  Sure.  But most of the time it causes far more pain than it prevents.

What should be done differently?

I think attempting to create a single, unified API that can solve every problem via reconfiguration is a really bad idea.  With WCF we can configure every single aspect of the end point, the transport, the channel, etc.  There are defaults for many things, but even using the defaults where possible won’t get your configuration much below 20 lines of app.config mess. 

Instead, I would like to see specialized APIs to tackle each type of problem.  (We’re already making a little progress on this front with things like NServiceBus, which provides an API that is tailored to the types of problems service buses are meant to solve.)  Instead of requiring extensive configuration, the APIs should adopt intelligent (but swappable) conventions, allowing users to get up and running with the API with near-zero configuration while still providing plenty of hooks for extensibility.  I think sacrificing some flexibility in order to avoid complexity is a good trade. 

Another problem: right now, I’d say that making synchronous calls is the path-of-least-resistance when using WCF.  Sure, WCF supports asynchronous calls, but I think most developers fall into the easy trap of making synchronous calls. I think the remote APIs should be asynchronous-by-default.  It should take (some) extra work to make synchronous inter-process calls, thereby redirecting developers towards a better design for their distributed systems.  Making synchronous web service calls is a good way to kill your system’s performance.

One common use case I keep bumping in to is making a Remote Procedure Call to a service on another physical machine.  Handling that with WCF requires extensive configuration on both ends.  I’m not sure exactly what I’d like to see on the server-side, but perhaps something like this (inspired by StructureMap):

public class MyServiceObjects : ServiceRegistry
    public MyServiceObjects()
        //This would load default conventions for things like 
        //channel and endpoint settings, but it could be replaced
        //by your own conventions. 
        //By default, expose services over a TCP channel
        //Changing to an alternate channel should still be trivial. 

Note that there are no app.config settings needed for this.  All the configuration data would come from the conventions (defined in code) or would be explicitly specified in the registry.  Are there downsides to this?  Sure: I can’t decide to change how my services are exposed without recompiling my application.  I don’t see that as being a big loss.

Client-side, I think it should be very clear when you are using a remote object.  The remote object should not pass for a local one (at least not without having to jump through a small hoop; after all, there are going to be times when treating it as a local object makes perfect sense).  The proxy should be asynchronous by default and support batching remote calls.  Here’s what my previous example might look like with such an API:

public void ListResults(string remoteSourceUrl, int count)
    var proxy = RemoteProxy.For<IDataSource>(remoteSourceUrl);

    using (proxy.BeginBatch())
        for (int i=0; i < count; i++)
            //The first lambda is the call on the data source.
            //The second lambda is the callback to run when the 
            //remote call completes. 
            proxy.Call(ds => ds.GetItem(i), item => Console.WriteLine(item));

So what do we do?

I’m not sure.  Microsoft has shown no real hint of backing off from WCF despite the overwhelming negative feelings that most of the .NET community has about it, but I don’t see a lot of effort by the community to develop alternatives aside from the various service buses.  Maybe I’m overlooking something (if so, let me know).  I’d love to work on something like this, but my workload is already overwhelming me.  If there’s an effort by someone out there to implement something along these lines though, I’d be game for helping out when/where I can.