ServicesResourcesConferences Our TeamWeblogsAboutContact
     
  

Developer Resources

  Architecture Briefings
  Articles
  Conversations
  Tools and Samples
  Books

HOWTO: Change a Message in the sink stack

Question

I'm playing around with Sinks and now I'm facing the following problem:

Let's suppose I want to intercept with a sink the call to the following method of a given class, my goal is to preprocess all the calls to this method to modify the input parameter (speech) in order to translate it into a different string:

public void Talk(string speech) { 
   Console.WriteLine(speech); 
}

And here there is my IMessageSink implementation, I can intercept the call pretty well but I don't know how to modify the message before forwarding it to the next sink on the chain:

public class TranslationSink : IMessageSink { ..... ...... 

 public IMessage SyncProcessMessage (IMessage msg) { 
   IMessage ret = null; 
   IMethodCallMessage mcm = msg as IMethodCallMessage;
   if (mcm != null) { 
      if (mcm.MethodName == "Talk") { 
         // Here I get the current value for the speech string 
         string speech = (string)mcm.InArgs[0];

         // Now I would like to modify such parameter 
         // just before the method is executed 
         string newspeech = DoSomeThing(speech)

         // Where should I put the modified parameter now? 
         mcm.InArgs[0] = newspeech;  
         // this doesn't work! It compiles but don't have any effect
      }
   } 
   ret = next.SyncProcessMessage (msg); return ret; 
 } 
  ..... 
  ... 
}

I stepped through the code and i can read successfully the value of InArgs[0] on the IMethodCallMessage interface The problem arise when i try to change such value since it seems that property is read-only, any attempt to set a new value (i.e. mcm.InArgs = newvalue) is ignored.

Maybe I should create a new MethodCall object based on the same properties of the original one, except for the parameter i want to change, and forward its IMethodCallMessage interface through the chain? I'm trying to figure it out but that class is not that highly documented.

Answer

Change your message modification code from something like this:

if (mcm.MethodName == "Talk") { 
   string speech = (string) mcm.InArgs[0]; 
   string newspeech = DoSomething(speech) 
   mcm.InArgs[0] = newspeech; 
}

to this:

if (mcm.MethodName == "Talk") { 
   MethodCallMessageWrapper newMsg = new MethodCallMessageWrapper(mcm); 
   object[] methodArgs = newMsg.Args; // Fetch the args 
   string speech = (string)methodArgs[0]; 
   string newspeech = DoSomething(speech);
   methodArgs[0] = newspeech;
   newMsg.Args = methodArgs; // Modify the args 
   msg = newMsg; // Point to the modified message before forwarding 
}

And see how that works out.

The MethodCallMessageWrapper class has a setter for the Args property, whereas the IMethodCallMessage interface only has a getter - which returns a copy of the args. That's why your modifications weren't kicking in - you were modifying a clone of the args array.






 

© 2002-2006 by Thinktecture, Ingo Rammer and Christian Weyer. All rights reserved. | Contact | Impressum