.NET Remoting (or “what the cool kids are NOT doing”)

Today, in a fit of insanity curiosity, I decided to find out how hard it would be to communicate between two CLR applications using .NET remoting. This is how far behind the bleeding edge I am — all the cool kids are using WCF, web services or what have you.

Nevertheless, the scenario is simple: I want to have two console applications, one of which should display messages sent from the other. This is how I went about it:

First, create an assembly that contains the class of the object we want to share between applications. I opted to call the class RemoteEndpoint. The docs say it needs to inherit MarshalByRefObject, so that’s what I’ll make it do then. Also, because events are nice, I’m defining a delegate type and a MessageReceivedEventArgs type for passing things around:

using System;

namespace CommonTypes
{
    public class MessageReceivedEventArgs : EventArgs
    {
        public MessageReceivedEventArgs(string message)
        {
            Message = message;
        }

        private string m_message;

        public string Message
        {
            get { return m_message; }
            set { m_message = value; }
        }
    }

    public delegate void MessageReceivedEvent(MessageReceivedEventArgs args);

    public class RemoteEndpoint : MarshalByRefObject
    {
        public RemoteEndpoint()
        {
            Console.WriteLine("Ctor called, ready to receive remote calls.");
        }

        public event MessageReceivedEvent MessageReceved;

        public void ReceiveMessage(string message)
        {
            if(MessageReceved == null)
                return;

            MessageReceved(new MessageReceivedEventArgs(message));
        }
    }
}

I then created two console applications, and referenced the project containing the above types and the BCL System.Runtime.Remoting in both of them.

Next up, the console apps themselves. Here’s Recipient:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using CommonTypes;

namespace Recipient
{
    public class Program
    {
        [STAThread]
        public static void Main(string[] args)
        {
            ChannelServices.RegisterChannel(new TcpChannel(1234), false);

            RemoteEndpoint endPoint = new RemoteEndpoint();
            endPoint.MessageReceved += Program_MessageReceved;

            RemotingServices.Marshal(endPoint, "RemoteEndpoint");

            Console.WriteLine("Hit enter to exit");
            Console.ReadLine();
        }

        static void Program_MessageReceved(MessageReceivedEventArgs args)
        {
            Console.WriteLine(args.Message);
        }
    }
}

Not rocket science. All we need to do is register a TCP channel, specify a port for it, create the object we want to share and then RemotingServices.Marshal() it with a URI we can use at the other end. Speaking of which:

using System;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using CommonTypes;

namespace Sender
{
    public class Program
    {
        public static void Main(string[] args)
        {
            ChannelServices.RegisterChannel(new TcpChannel(), false);
            RemoteEndpoint endPoint =
                (RemoteEndpoint) Activator.GetObject(typeof (RemoteEndpoint), "tcp://localhost:1234/RemoteEndpoint");

            Console.WriteLine("Hit enter to send a message. Q to stop.");

            string line = Console.ReadLine();
            while(line.Trim().ToLowerInvariant() != "q")
            {
                Console.WriteLine("Sending a message.");
                endPoint.ReceiveMessage(line);
                line = Console.ReadLine();
            }

            Console.WriteLine("So long, and thanks for all the fish!");
        }
    }
}

Here we instantiate the remote object by way of Activator.GetObject. Since it’s published under the name “RemoteEndpoint” on a TcpChannel on localhost, port 1234, the URI is tcp://localhost:1234/RemoteEndpoint. Now, every time the user hits Enter, if the line isn’t the magic “Q”, the line gets sent to the remote recipient.

Mandatory note: this is just me learning a new trick, not production quality code.

Edit: As evidenced by the fact that I had written:

while(line.Trim().ToLowerInvariant() != "Q")

Gotta love them lowercase Q’s. (Thanks for pointing that out to me, J 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *