Easy remote communication without WCF

If you´ve read my previous posts about why I deem WCF more of a problem than a solution and how I think we should switch to asynchronous only communication in distributed application, you might be wondering, how this could be done in an easy way.

Since a truely simple example to get started with WCF still is drawing quite some traffic to this blog, let me pick up on that and show you, how to accomplish the same but much easier with an async communication API.

For simplicities sake let me put all the code of client and server in just one file. In the following sections I´ll walk you through this file. The service it implements is simple. I start with a ping service. The client sends a text message to the server; the server dumps the text to the console.

The implementation is based on Microsoft´s CCR and two layers of abstraction encapsulating the CCR as well as WCF. See, I´m not saying WCF is bad per se; I just don´t want to use it in my application code. As a low level communication infrastructure the WCF is just great.

The two layers of abstraction on top of the CCR and WCF are the CCR Space and Xcoordination Application Space (or AppSpace for short). Both are open source. The CCR Space wraps CCR concepts and the AppSpace to make it easier to work with them. And the AppSpace enables you to use CCR ports for remote communication.

From now on I´ll refer to both as “the Spaces” or “Space based communication”.

If you want to follow along my samples download the binaries from the CCR Space project site and reference the CCRSpace.dll as well as microsoft.ccr.core.dll.

Service implementation

With the Spaces it´s easy to define a service. No special service contract is needed. You can use any method with just one parameter and no return value. The parameter type needs to be serializable, though. Use the [Seriablizable] attribute for your own message types.

    1 using System;

    2 using System.Threading;

    3 

    4 using CcrSpaces.Core;

    5 

    6 namespace AsyncSimple.Server

    7 {

    8     public class Program

    9     {

   10         public static void Ping(string name)

   11         {

   12             Console.WriteLine("SERVER - Processing Ping('{0}')", name);

   13         }

Of course there are ways to define services with several methods (or to say it differently: which can process different message types). But for now let´s keep the service as simple as possible, like I did in the WCF sample.

Service hosting

Next you need to host the service. For that you create a CCR Space (CcrSpace) and configure it as a host using a certain transport layer (line 17). I´m using WCF with net.tcp binding as a transport, but I could also have used raw TCP sockets or WCF with named pipes or Jabber or MSMQ.

By passing “wcf.port=8000” to the configuration method the transport layer type is selected and the listening port specified.

   15 public static void Main(object state)

   16 {

   17     using(var serverSpace = new CcrSpace().ConfigureAsHost("wcf.port=8000"))

   18     {

   19         var chService = serverSpace.CreateChannel<string>(Ping);

   20         serverSpace.HostPort(chService, "Ping");

   21 

   22         Console.WriteLine("SERVER - Running...");

   23         Console.ReadLine(); // keep alive

   24     }

   25 }

Once the Space is running, the service is bound to a channel (line 19). The channel is used to send messages to the service.

To make the channel available for remote clients it´s hosted in the Space (line 20). This defines an address for the service listening on the channel. The service can now be reached over all registered transports by using their addresses combined with the service name; here that´s “localhost:8000” for WCF plus “Ping”: localhost:8000/Ping.

Is you leave out ConfigureAsHost() and HostPort() you get local communication instead of remote. With the Spaces it´s easy to switch between the two communication modes. The communication paradigm stays the same. No other changes are needed to your code. The only differene between local and remote async communication is hosting a port or not (and how you connect to a port depending on it being local or remote).

Client implementation

Since this is a self-contained example the client starts with kicking off the server:

   30 namespace AsyncSimple.Client

   31 {

   32     class Program

   33     {

   34         static void Main(string[] args)

   35         {

   36             ThreadPool.QueueUserWorkItem(AsyncSimple.Server.Program.Main);

Then comes the important part: connecting the client to the server and calling the service:

   38 using(var clientSpace = new CcrSpace().ConfigureAsHost("wcf.port=0"))

   39 {

   40     var chServiceProxy = clientSpace.ConnectToPort<string>("localhost:8000/Ping");

   41 

   42     chServiceProxy.Post("world!");

   43 

   44     Console.ReadLine(); // keep alive

   45 }

Like the server the client needs to instantiate a CCR Space. Async communication is symmetric. So both parties communicating need to look the same. Both “are” Spaces.

Since the client does not publish any services, its port is of no interest so I set it to 0 for the AppSpace to choose. But of course the client Space needs to use the same transport layer like the server (line 38).

Then the client connects to the service´s remote port using its address (line 40). From now on the client can send messages to the service through the channel (line 42).

Summary

That´s it. This is how easy async communication can be. This is how easy remote communication can be. The application does not bother itself with complicated WCF configuration. Think of all the concepts and terms you need to understand for that, e.g. ServiceContract, OperationContract, ServiceBehaviour, InstanceContextMode, ServiceHost, and ChannelFactory.

With the Spaces you just need a CcrSpace and a Port (aka channel). Create a space, create a channel and bind your service methode to it, host/publish the channel on the server, connect to the channel on the client.

Once you grog the communication paradigm (async message oriented communication) it´s only 4 lines of code to set up service and client.

And now tell me: Can it become any easier, and stay true to the nature of remote communication? I doubt it.

Please get me right, I´m not saying those Spaces are a panacea or the ultimate communication API. I´m just challenging WCF´s position as the one-size-fits-all solution to remote communication. There are alternatives to WCF. Service busses like NServiceBus or Mass Transit are alternatives, but I think to use them seems to be an overkill for developers in many scenarios. That´s why I´m trying to show you a another alternative: Space based communication. It kind of looks like regular service communication, but it´s all asynchronous like the busses.

Ok, if this still sounds interesting to you, you sure have a couple of questions. How to do return a result from a service? How to notify clients of service progress? How to deal with service failures? Bear with me, I´ll try to answer them in the next couple of postings. For now I just wanted to show you how easy it is to get async remote communication running at all.

2 Comments

  • One-way-communication is easy, but usually you communicate with a server because you want something from it.

    I think the main problem of most people is not this kind of one-way-usage, but instead how to achieve async comm when you have a GUI, pull data from a server depending on input and display it somewhere.

  • Can you please allow a download of samples so we dont have to cut and paste.

Comments have been disabled for this content.