Friday, October 30, 2009

Logging proxy

I learnt today that I can create a proxy that intercepts calls to an object, do anything with the call and forward the call to the appropriate object. The same is true for the results. The whole thing is implemented by using a RealProxy implementation. I will demonstrate the functionality with .NET Remoting.

The common interface

namespace Common
{
public interface IServer
{
int Add(int a, int b);
}
}

The server implementation

using Common;

namespace Server
{
class ServerImpl: MarshalByRefObject, IServer
{
#region IServer Members

public int Add(int a, int b)
{
return a + b;
}

#endregion

public override object InitializeLifetimeService()
{
return null;
}
}
}

The server loop

static void Main()
{
// Windows Forms settings
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

// Remoting loop
RemotingServices.Marshal(new SzerverImplementacio(), "Server");
ChannelServices.RegisterChannel(new TcpChannel(8080), false);

// Windows Froms Window
Application.Run(new Form1());
}

The logging proxy

using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels;
using System.Collections;
 
namespace Kliens
{
    public class LogProxy : RealProxy
    {
        String uri;
        MarshalByRefObject obj;
        IMessageSink _sinkChain;
 
        public LogProxy(Type type, string uri) : base(type)
        {
            this.uri = uri;
 
            IChannel[] registeredChannels = ChannelServices.RegisteredChannels;
            foreach (IChannel chnl in registeredChannels)
            {
                if (chnl is IChannelSender)
                {
                    IChannelSender chnlSender = (IChannelSender)chnl;
                    _sinkChain = chnlSender.CreateMessageSink(uri, null, out uri);
                    if (_sinkChain != null)
                        break;
                }
            } 
 
            if (_sinkChain == null)
            {
                throw new Exception("No channel has been found for " + uri);
            }
 
        }
 
        public override IMessage Invoke(IMessage msg)
        {
            Console.WriteLine("LogProxy.Invoke Start");
            Console.WriteLine("");
 
            // Set message URI
            msg.Properties["__Uri"] = uri;
 
            // List call properties
            Console.WriteLine("Call properties:");
            foreach (var key in msg.Properties.Keys)
            {
                Console.WriteLine("{0}: {1}", key, msg.Properties[key]);
                if (key.ToString() == "__Args")
                {
                    Console.WriteLine("Arguments:");
 
                    object[] args = (object[])msg.Properties[key];
                    foreach (var arg in args)
                    {
                        Console.WriteLine("arg: {0}", arg);
                    }
                }
            }
 
            // Process the request mesage
            IMessage retMsg = _sinkChain.SyncProcessMessage(msg);
 
            // List return properties
            Console.WriteLine("Return properties:");
            foreach (var key in retMsg.Properties.Keys)
            {
                Console.WriteLine("{0}: {1}", key, retMsg.Properties[key]);
            }
 
            // Process the return message
            return retMsg;
 
        }
    }
}

Call the server from the client

// Without logging proxy:
// IServer server = (IServer)Activator.GetObject(typeof(IServer), "tcp://localhost:8080/Server");
 
TcpChannel chnl = new TcpChannel();
ChannelServices.RegisterChannel(chnl, false);
 
LogProxy prx = new LogProxy(typeof(IServer), "Tcp://localhost:8080/Server");
IServer server = (IServer)prx.GetTransparentProxy();
MessageBox.Show(server.Add(2, 3).ToString());

Result

All the call end response properties will be listed in the Output window (or in the Console). The call will happen as there were no proxy class taking part in the call.

Apart Remoting this is a good solution for generating any kind of proxies:

  • Virtual proxies
  • Security proxies

RealProxy is a good extension point for an application.