18.11 Creating Proxies for Message Interception

 <  Day Day Up  >  

You want to create a custom proxy to intercept method calls before they are passed to a sink.


Technique

As you already have seen in Recipe 18.1, "Creating a Remotable Object," the client application does not invoke the remote object directly, but it uses a proxy instead. .NET Remoting uses two kinds of proxies: a transparent and a real proxy. The transparent proxy looks like the remote object with the same methods as the remote object. However, the transparent proxy does nothing more than forward the method calls to the real proxy by calling the method Invoke . The responsibility of the real proxy is to create a message from the method and to pass the message to the message sinks and into the channel.

Figure 18.2 shows the transparent proxy and the real proxy that are called by the client. In the example, the client invokes the Greeting method of the transparent proxy. The method Greeting is also available with the remote object. The transparent proxy in turn invokes the Invoke method of the real proxy.

Figure 18.2. A client invoking the Greeting method of the transparent proxy.

graphics/18fig02.gif

To create a custom proxy, you have to create a class that derives from RealProxy ; in the example, the class is named CustomProxy . The constructor of the class CustomProxy calls the constructor of the RealProxy , where it creates a transparent proxy of the type that is passed. The second argument of the CustomProxy constructor defines the URL to the remote object. This URL is used to create a message sink with the help of a channel. ChannelServices.RegisteredChannels returns an array of all channels that are registered with the remoting runtime:

 
 public CustomProxy(Type type, string url)     : base(type) {     this.url = url;     foreach (IChannel channel in ChannelServices.RegisteredChannels)     {         IChannelSender channelSender = channel as IChannelSender;         if (channelSender != null)         {             string uri;             sink = channelSender.CreateMessageSink(url, null,                                                    out uri);             if (sink != null)                 break;         }     }     if (sink == null)     {         throw new Exception("A channel supporting the URL "                             + couldn't be found!");     } } 

With the custom proxy class, you have to override the method Invoke . This method is called for any method that is invoked with the transparent proxy. In the implementation, the message representing the method call is passed to the sink object created earlier with the method SyncProcessMessage to process the method call with the remote object. SyncProcessMessage returns a return message that is returned from the Invoke method:

 
 public override IMessage Invoke(IMessage msg) {     //...     IMessage returnMessage = sink.SyncProcessMessage(msg);     //...     return returnMessage; } 

In Listing 18.4, you can see the complete implementation of the Invoke method that displays information about the message that represents the method call.

Listing 18.4 A Custom Proxy Implementation
 public override IMessage Invoke(IMessage msg) {     Console.WriteLine("proxy started");     if (msg is IMethodCallMessage)         Console.WriteLine("IMethodCallMessage");     if (msg is IMethodReturnMessage)         Console.WriteLine("IMethodReturnMessage");     Type msgType = msg.GetType();     Console.WriteLine("Message Type: {0}", msgType.ToString());     Console.WriteLine("Message Properties");     IDictionary dict = msg.Properties;     // Set the '__Uri' property of 'IMessage' to 'URI' property of 'ObjRef'.     dict["__Uri"] = this.url;     IDictionaryEnumerator dictEnum =             (IDictionaryEnumerator)dict.GetEnumerator();     while (dictEnum.MoveNext())     {         object key = dictEnum.Key;         string keyName = key.ToString();         object val = dictEnum.Value;         Console.WriteLine("\t{0} : {1}", keyName, dictEnum.Value);         if (keyName == "__Args")         {             object[] args = (object[])val;             for (int i = 0; i < args.Length; i++)             {                Console.WriteLine("\t\targ: {0} value: {1}", i, args[i]);             }         }         if ((keyName == "__MethodSignature") && (val != null))         {             object[] args = (object[])val;             for (int i = 0; i < args.Length; i++)             {                 Console.WriteLine("\t\targ: {0} value: {1}", i, args[i]);             }         }     }     IMessage returnMessage = sink.SyncProcessMessage(msg);     IMethodReturnMessage methodReturnMessage =             (IMethodReturnMessage)returnMessage;     Console.WriteLine("IMethodReturnMessage.ReturnValue: {0}",                       methodReturnMessage.ReturnValue);     Console.WriteLine("proxy finished");     return returnMessage; } 

For the custom proxy, you have to create an instance of the CustomProxy class in the client application and get the transparent proxy with a method of the base class RealProxy . GetTransparentProxy returns the transparent proxy that can be used by the client to invoke the methods of the remote object:

 
 RemotingConfiguration.Configure("11_client.exe.config"); _11_CustomProxy.CustomProxy proxy =         new _11_CustomProxy.CustomProxy(typeof(_1_RemoteObject.RemoteObject),                                         "http://localhost:8088/Demo"); _1_RemoteObject.RemoteObject obj =         (_1_RemoteObject.RemoteObject)proxy.GetTransparentProxy(); string s = obj.Greeting("Christian"); 

Figure 18.3 shows the output of the client application that displays the information about the message inside the custom proxy.

Figure 18.3. Console output using the custom proxy.

graphics/18fig03.gif

Comments

With a custom proxy, you create a class that derives from the RealProxy class, and you have to override the method Invoke . In the Invoke method, you have full access to the message, so you can change it accordingly or select different servers, depending on their load.

Using a custom proxy, you lose the configurability of the remote object with the client. In the client, you have to create an instance of the custom proxy and ask for the transparent proxy. You can make a different approach to intercepting methods by creating channel sinks. Using proxies just has an advantage if you don't want to use channels and if you want to intercept calls to local objects.

 <  Day Day Up  >  


Microsoft Visual C# .Net 2003
Microsoft Visual C *. NET 2003 development skills Daquan
ISBN: 7508427505
EAN: 2147483647
Year: 2003
Pages: 440

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net