Monthly Archives: May 2008

.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 :)

Redo from start…

I got my copy of Calculus Lite, and after hesitating for a couple of days, began reading about derivatives. Much to my amazement, I was able to pick up the trail, at least to some extent. Doing the exercises brought to mind how much I used to enjoy working with simple equations back in the day.

I’m clearly making progress with regards to the problem I was having with math. It’s definitely not gone — long equations still confuse me because it takes time to parse and my pattern matching engine is still untrained for these cases, but something feels different. I tried to describe the feeling to my wife: It’s like looking at a drawing composed of innumerable lines that don’t make any sense, but all of a sudden, a hint of a pattern emerges. Just enough to convince me that the pattern is there, and I have the capacity to learn it, if I push it a bit.

It’s a lot like re-learning math from scratch. I’m a bit intimidated, but also very excited. :)

Everything was better back in the day…

… including people’s understanding of technology.

If you’re like me, you’re always grimacing at the CSI guys blowing up CCTV images like there’s no tomorrow. Today, watching Due South, a series from 1994, I come across this gem:

It’s not going to do you any good. [A character in some movie] had film, you guys are stuck with tape. 720 pixels across, and if you have fifty people on the screen, that’s… 14 pixels per face. Which means you’re looking at like two pixels per nose. And no matter how much I blow up the image, each nose is going to look like two little dots.

Take that, CSI!