Can ServiceStack replace .NET remoting?

1,133 views
Skip to first unread message

Dave Nay

unread,
Feb 21, 2012, 9:21:12 AM2/21/12
to servic...@googlegroups.com
We currently have a legacy application that uses .NET remoting to communicate between a WinForms client and a server application. I am investigating replacing the tightly coupled .NET remoting with a message based structure.

My primary questions are
  1. Is SS appropriate for use outside of a "web" application?
  2. What is the performance of SS? We are currently using binary serialization to transmit image data from server to client (~10-20 frames per second depending on image size) and any new infrastructure would need to handle this acceptably (I don't have a good definition of "acceptably" though).
  3. How does SS compare with using a Service Bus? They seem very similar so far from my reading.
I appreciate any insight you can give me.

Thanks,
Dave

Demis Bellot

unread,
Feb 21, 2012, 9:57:37 AM2/21/12
to servic...@googlegroups.com
At the moment there are 2 non-HTTP modes that allow you to invoke your services outside a HTTP Context: RedisMqHost + RCON Server and we're also looking at integrating pure TCP host + Web Socket server in the future.

We're using the Redis MQ Host in Careers 2.0 but unfortunately haven't had the time to document it properly more than this:

The beauty of the ServiceStack approach is that your same Web Service can also be invoked outside of a HTTP context (above) and if you send a message to the /asynconeway endpoint (i.e. as done in client.SendOneWay()) it will automatically publish your Request DTO into a MQ to defer execution to any Redis MQ Host that's running 


After we get this next release notes out, we'll look at creating more doco + example project that makes use of this.

Is SS appropriate for use outside of a "web" application?

There are 2 primary hosts AppHostBase + AppHostHttpListenerBase. Inside those you can also start a Redis MQ Host and RCON server to start processing requests via those endpoints.
The Starter template projects show different host projects (e.g ASP.NET, Console, Windows Service, etc).

What is the performance of SS? We are currently using binary serialization to transmit image data from server to client (~10-20 frames per second depending on image size) and any new infrastructure would need to handle this acceptably (I don't have a good definition of "acceptably" though).

Note the Binary Formatter that .NET remoting uses is quite slow (even slower than their XML Serializer). 

ProtoBuf is the fastest but requires explicit indexes for each property. As it's an external dependency ProtoBuf isn't automatically included in ServiceStack, but can be easily added as seen in these Integration (ASP.NET + HttpListener) tests: https://github.com/ServiceStack/ServiceStack/commit/1ef7eb3b5a016fba37b5eb31286ff590920eec58

ServiceStack's JSV + JSON text serializers come closest to matching it.

For non-HTTP here are some benchmarks to test the RedisMQ Host:

At my work pc I'm getting over 5k req/s, though YMMV. Though the Redis MQ Host uses Redis as a broker (so its not point to point) but lets you communicate without knowing the endpoints for all your apps (by just subscribing to same redis-server).

I don't have any benchmarks for the RCON server (which was contributed by John MacCarthurs) but it's an efficient protocol and it is point to point so I imagine it will do well.

How does SS compare with using a Service Bus? They seem very similar so far from my reading.

I don't like Service Buses as they usually require all participants to subscribe to the same bus restricting its use. It makes your services less re-usable and services should be about exposing your systems capabilities in as interoperable and re-usable way possible. Since every platform has a good HTTP client, this is the most interoperable way to expose your services. 

Though as described above ServiceStack lets you write a service once and have it exposed on a variety of different Endpoints and Formats. Includes JSON, JSV, XML, HTML/CSV, SOAP 1.1/1.2 as well non-http Redis MQ + RCON endpoints.

Cheers,




Dave Nay

unread,
Feb 21, 2012, 10:09:24 AM2/21/12
to servic...@googlegroups.com
Thank you for the response...that's a lot to digest for a new guy. ;-)

Dave Nay

unread,
Feb 25, 2012, 5:46:31 PM2/25/12
to servic...@googlegroups.com
Hi again Demis,

As I said, that was a lot for a newb to read through, but I think I have a grasp of it now.

A couple more questions to clarify....

Is the RedisMQHost or RCON required to function outside of the ASP/IIS stack? It appears as if I only wanted or needed to use ServiceStack alone, all I would need is the use the AppHostHttpListenerBase class in my server application, and then my client application would simply talk to this service through the HTTP handler that is provided by AppHostHttpListenerBase ? Would I gain anything by using the RedisMQHost? I don't particularly need any of the off-line queued messages provided by Redis, I am simply looking to replace the method-signature based API that is forced by .NET Remoting and WCF with a message based DTO command-response system.

This is for a desktop client/server application so I really want to make sure that I am not attempting to utilize a completely inappropriate for my applications scenario.

I thank you again for the in-depth wiki pages, test code and examples, they have helped me a lot in trying to understand how to use ServiceStack, and I have tons more to read and a few prototype applications to go before I will feel confident.

Dave

Demis Bellot

unread,
Feb 25, 2012, 6:02:03 PM2/25/12
to servic...@googlegroups.com
Is the RedisMQHost or RCON required to function outside of the ASP/IIS stack? 

No neither is required and none of them are setup by default - you have to explicitly start them with the registered services you want available via those endpoints.

It appears as if I only wanted or needed to use ServiceStack alone, all I would need is the use the AppHostHttpListenerBase class in my server application, and then my client application would simply talk to this service through the HTTP handler that is provided by AppHostHttpListenerBase ?

Correct. The only thing the AppHostHttpListenerBase class starts is the HttpListener to accept HTTP service requests, nothing else.

Would I gain anything by using the RedisMQHost?

Not if you or your clients don't use it. There are many benefits of using a MQ, durable and reliable messaging, deferred execution, natural load-balancing, de-couple publisher from receiver, etc. 

 I don't particularly need any of the off-line queued messages provided by Redis, I am simply looking to replace the method-signature based API that is forced by .NET Remoting and WCF with a message based DTO command-response system.

Then it sounds like you don't need it, and you don't have to worry as it's not setup or required by default.

This is for a desktop client/server application so I really want to make sure that I am not attempting to utilize a completely inappropriate for my applications scenario.

Sure, use HTTP - it's ubiquitous, has rich debugging and tooling support and works.

I thank you again for the in-depth wiki pages, test code and examples, they have helped me a lot in trying to understand how to use ServiceStack, and I have tons more to read and a few prototype applications to go before I will feel confident.

Pleasure :)


Cheers,

Dave Nay

unread,
Feb 25, 2012, 6:10:12 PM2/25/12
to servic...@googlegroups.com
The client (application) is fully under our control and can be designed as-needed to communicate with the server. The client (end customer) will never access the server outside of the context of the provided WinForms client application that we provide as part of our software suite. To further clarify, this used to be a monolithic VB6 application that was split into client & server applications and re-written in .NET for performance reasons. At the time, none of us were familiar with the best technology and I believe our choice of .NET remoting was not the correct choice.

Demis Bellot

unread,
Feb 25, 2012, 6:52:17 PM2/25/12
to servic...@googlegroups.com
If it helps I can't think of a situation where .NET Remoting is a good idea - Unless of course you want to limit the accessibility and usefulness of your servers services to your bespoke .NET clients forever :) 

.NET Remoting still makes use of .NET BinaryFormatter (if I'm not mistaken) which remains in the elite group of binary serializers that's slower than Microsoft's Xml Serializer, so I don't expect major performance gains here.
Using binary makes debugging and introspection of network traffic harder - so using a slow binary serializer is effectively a lose, lose situation.

IMO I find trying to communicate remotely services without well-defined DTOs for your wire representation to be a losing proposition. 

I generally prefer clean, fast, simple technology - they're less complex to maintain, easier to rationale about, easier to debug and in many cases end up being faster. 

Although it looks like you just want something to work well across client/server in which case HTTP is your best choice.

If instead you do want a simple, extensible fast TCP protocol format for point-to-point communication I recommend either the Redis or Memcached wire formats, they're simple, fast, clean, binary-safe and work well over a telnet session:

Cheers,

Dave Nay

unread,
Feb 25, 2012, 10:59:11 PM2/25/12
to servic...@googlegroups.com
Hi again Demis,

I am still playing with RedisMQ and am having some difficulty. Does RedisMQ within ServiceStack require a separate instance of Redis or is it "built in"?

Do you have a quick example of what the client would look like for using RedisMQ to connect to a remote RedisMQ server? At this point I am thinking that the client and server applications look nearly identical with both of them utilizing the AppHostHttpListenerBase and then setting up RedisMQ in both:


This wiki page gives an example of what appears to be messaging from within the same application, and I am trying to figure out how this functionality would be split between client and server applications (and what parts need to be duplicated in both.)

Dave

Demis Bellot

unread,
Feb 26, 2012, 12:55:57 AM2/26/12
to servic...@googlegroups.com
Redis is a  NoSQL datastore that runs as a network server. To start it you need to run an instance of redis-server either locally or remotely accessible.

Probably help to understand a bit of background behind Redis so you can get a better idea of how it works. 
A good start is this brief overview of Redis which also includes as how you can install it: 
http://stackoverflow.com/a/2760282/85785

The RedisMQ Host is in ServiceStack.Redis project which is a dependency on the ServiceStack NuGet package (if that's how you have ServiceStack installed).

At the moment the there is not much documentation available and will look to improve this after I get the next release of ServiceStack out.

You can look through the tests to get a better idea of how it works, especially the Request / Reply example:

Basically the RedisMQ runs as a separate background thread you start from inside your AppHostHttpListenerBase.
For duplex communication each client and server will require its own AppHostHttpListenerBase + RedisMQ Host.
Although unless your server is going to call HTTP services on the client you don't need it. 
But I've included a simple example of what a client / server with HTTP + RedisMQ enabled would look like (note was done in a text editor so could be compile errors): 

//Shared DTOs

public class Hello { 
public string Name { get; set; } 
}
public class HelloResponse { 
public string Result { get; set; } 
}


//Server

public class HelloService : IService<Hello> {
    public void Execute (Hello req) { 
    return new HelloResponse { Result = "Hello, " + req.Name } 
    }
}
 
public class ServerAppHost : AppHostHttpListenerBase {
    public void ServerAppHost() 
    : base ("Hello Server Services", typeof(HelloService).Assembly) {}
    
    public void Configure(Container container) {
        
base.Routes
   .Add<Hello>("/hello")
   .Add<Hello>("/hello/{Name}");

var redisFactory = new PooledRedisClientManager("localhost:6379");
var mqHost = new RedisMqHost(redisFactory, noOfRetries:2, null);

//Server - MQ Service Impl:

 //Listens for 'Hello' messages sent with 'mqClient.Publish(new Hello { Name = "Client" });'
mqHost.RegisterHandler<Hello>(m => 
   new HelloResponse { Result = "Hello, " + m.GetBody().Name });
mqHost.Start(); //Starts listening for messages
    }
}
var serverAppHost = new ServerAppHost();
serverAppHost.Init(); 
serverAppHost.Start("http://serverhost:81"); //Starts HttpListener listening on 81
Console.ReadLine(); //Block the server from exiting (i.e. if running inside Console App)


//Client

public class ClientAppHost : AppHostHttpListenerBase {
    public void ClientAppHost() 
    : base ("Hello Client Services", typeof(HelloService).Assembly) {}
    
    public void Configure(Container container) {

var redisFactory = new PooledRedisClientManager("redishost:6379");
var mqHost = new RedisMqHost(redisFactory, noOfRetries:2, null);

//Client - MQ Service Impl:
//Listens for 'HelloResponse' as returned by the 'Hello' service on the server
mqHost.RegisterHandler<HelloResponse>(m => {  
   Consle.Log("Received: " + m.GetBody().Result);  //Fired 
});
mqHost.Start(); //Starts listening for messages
    }
}
var clientAppHost = new ClientAppHost();
clientAppHost.Init(); 
clientAppHost.Start("http://clienthost:82"); //Starts HttpListener listening on 81
Console.ReadLine(); //Block the server from exiting (i.e. if running inside Console App)


With the above configuration the client can talk to the server with:


var mqClient = mqHost.CreateMessageQueueClient();
mqClient.Publish(new Hello { Name = "Client 1" });

The first RedisMQ host listening to the 'Hello' message (i.e. the server) will receive the message. 
When the server returns a 'HelloResponse' message it gets put on the 'HelloResponse' Inbox Queue and the first RedisMQ Host listening to the 'HelloResponse' message (i.e. Client) will have their callback fired.

However MQ's are normally used for async OneWay messages as any client host listening to 'HelloResponse' could receive the response message, and only 1 will, which is not guaranteed to be the client that sent the original message. For this reason you want to make use of the ReplyTo field of the Message for Request/Reply responses.

var uniqueCallbackQ = "mq:c1" + ":" Guid.NewGuid().ToString("N");
var clientMsg = new Message<Hello>(new Hello { Name = "Client 1" }) {
   ReplyTo =  uniqueCallbackQ
};
mqClient.Publish( clientMsg );
var response = mqClient.Get(clientMsg).ToMessage<HelloResponse>();  //Blocks this thread on the client until the reply message is received.


Note: The ReplyTo callback url could also be a ServiceStack endpoint that expects a 'HelloResponse' e.g.

var clientMsg = new Message<Hello>(new Hello { Name = "Client 1" }) {
};

In this case the server wont put the response message on the back on the MQ and will instead send the response directly to your client web service host.

There's a few MQ concepts covered above here, I invite you to do your own reading on MQ's in general as it works a little different to normal request/reply web services.

Cheers,
Reply all
Reply to author
Forward
0 new messages