Lightweight, fast and efficient WCF-replacement client-server API for remote procedure, method calls

Background (high-performance, easy-to-use client-server API and lightning-fast binary serializer)

There was a time when I was fed up with SOAP-based APIs, such as Web Services and their limitations. Either the performance was sub-par for the requirements of the project that I was working on, or it was difficult to pass complex data types (rather than primitives), there were restrictions on the type/content of remote method parameters… That, combined with message encoding format, being limited to XML, JSON or the extremely slow and bulky BinaryFormatter class in .NET overcomplicated things. All of that simply prompted me to one day write a proper, lightweight, fast and efficient remote call API, the bulk of it was done over two weekend days working non-stop at maximum capacity, but not before being first carefully planned and architected in advance, every detail of it. A specially-tailored extremely fast (orders of magnitude faster than XML) binary serializer was crafted specifically for this library. It can also be used standalone, as it’s as efficient as possible, making extremely compact output that occupies less memory than the actual .NET objects it represents. Take that, BinaryFormatter.

Reasons to use the light and fast client-server API instead of web-services or WCF

While, XML has its advantages, such as readability and debugging, I rarely derived any benefit from these in client-server scenarios. In theory, logging messages being transmitted can help identify any potential issues with the payload, in case an error occurs. However, in practice, in my personal experience, the actual XML encoded data is rarely of any value if proper logging is present on both the client and the server. Not a big issue, but for large amounts of data, XML is bulky and inefficient, but the biggest problem with traditional SOAP, is its limited ability to mix all kinds of data. For example, back in the days when I was using the ASP.NET Web Services API, it drove me nuts that I couldn’t define remote methods with, say, an array or stream of bytes as one parameter, a complex type with some binary content for another and some primitives for the rest. It just simply couldn’t be mixed that way, or at least that’s the way that I recall it. Binary data either needed to be converted to base64 or MTOM encoding enabled. So much trouble to accomplish a seemingly simple thing. That was.. counter-productive and annoying to say the least. Now, admittedly, I haven’t kept up with the latest developments in WCF and SOAP. I’m sure it’s come a long way, but last time I checked binary payload was generated using the BinaryFormatter class, which has been around since the first iterations of .NET and is slow, clunky and produces unjustifiably large output. No wonder many teams use third party, or develop their own client-server protocols, many of which are far easier to use and more robust than WCF (yes, it is great and flexible, but far from perfect).

Considerations

Obviously, this library wasn’t designed for interoperability and is limited to .NET. Other than that, the ease of use, simplicity and high-level of abstraction from the underlying protocol (call remote methods just like any other C# function) can make this a worthy choice for many projects. Message-level encryption can easily be programmed in, if desired, and an option to do so may be added in a future version, time permitting. Alternatively, for HTTP, TLS (SSL) encryption should be more than sufficient.

Introducing the high-performance RPC (remote procedure call) client-server API that blurs the line between local and remote methods

In this article I’ll introduce the binary-protocol remote procedure/method call (RPC) API that is very lightweight, fast, runs on top of IIS/ASP.NET by default, but can easily be adapted to use any protocol (sockets, shared memory, anything that can be wrapped inside a stream). The main idea behind it is sharing a DLL (a proxy generation mechanism wouldn’t be too difficult to develop, given demand) between the client and the server. That would allow sharing the same service signature and types. The complete source code is attached as a file below. It can be used in any way, no limitations, as long as credit is given in all derivative works. The compiled binaries are available on NuGet at the following URL: https://www.nuget.org/packages/EasyRpcBinaryService/
The .NET service API is easy to use and can be setup up within a few minutes with just a few lines of code. The package attached together with the source code contains a demo application that will launch a standalone IIS server process (ASP.NET development service) and send-receive data to/from it. The demo app is self-explanatory. Just launch the WinForms executable, click on the button and see the results. If it times out the first time while the server is being launched, try again.
The below example shows how easy it is to use the binary remote procedure call service with just a few lines of code.

How to use the C# client-server API

Define a service proxy signature as an abstract class deriving from the Server base class provided by the library:

public abstract class TestService : Server
{

    protected static IServerRequestTransport mDefaultTransport = new HttpTransport("http://localhost:61234/Handler.ashx");

    public static TestService GetProxy()
    {
        return Server.GetClientProxy<TestService>(mDefaultTransport);
    }//end method

    [ServerMethod]
    public abstract ServiceResponse GetResult(TestOperands mainOperands, int extraOperand, string incompleteValue);
}//end class

 

Define whatever object you want returned from the server:

[SerializableType]
public class ServiceResponse
{
    //Primitive value serialized and deserialized by the service pipeline
    [SerializableMember]
    public int ResultA { get; set; }

    //Composite value serialized and deserialized by the service pipeline
    [SerializableMember]
    public ServiceResponse ResultB { get; set; }

    //Array of composite values serialized and deserialized by the service pipeline
    [SerializableMember]
    public ServiceResponse[] ResultC { get; set; }

    //String serialized and deserialized by the service pipeline
    [SerializableMember]
    public string TextValue { get; set; }
}//end class

 

Define some non-primitive object to be passed as the parameter to the service:

[SerializableType]
public class TestOperands
{
    [SerializableMember]
    public int OperandA { get; set; }

    [SerializableMember]
    public int OperandB { get; set; }
}

 

That’s it you’re pretty much there. All you need to do is to compile your DLL and include it on both the client and the server. Then implement the body of your service method(s) as follows (very simple):

public class Handler : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {
        Server.ProcessRequest<TestServiceImplementation>(context.Request.InputStream, context.Response.OutputStream);
    }
 
    public bool IsReusable {
        get {
            return false;
        }
    }
 
    public class TestServiceImplementation : TestService
    {
        public override ServiceResponse GetResult(TestOperands mainOperands, int extraOperand, string incompleteValue)
        {
            ServiceResponse objResponse = new ServiceResponse();
 
            objResponse.ResultA = mainOperands.OperandA * mainOperands.OperandB + extraOperand;
 
            objResponse.ResultB = new ServiceResponse() { ResultA = 123};
 
            objResponse.ResultC = new ServiceResponse[] { new ServiceResponse() { ResultA = 1, TextValue = "1" }, new ServiceResponse() { ResultA = 2, TextValue = "2" }, new ServiceResponse() { ResultA = 3, TextValue = "3" } };
 
            objResponse.TextValue = incompleteValue + " world.";
            
            return objResponse;
        }
    }//end class
}

 

That’s it, all you have to do is run it now!

Please download the source code from here (no viruses, although Avast, at least, came up with a false positive on my own source code, fancy that):

Source code for lightweight, fast and effecient client-server remote-call API for C#






Information Error Confirmation required