ServicesResourcesConferences Our TeamWeblogsAboutContact
     
  

Developer Resources

  Architecture Briefings
  Articles
  Conversations
  Tools and Samples
  Books

HOWTO: Implement async handling in an IMessageSink

Question

I am using remoting with http/soap. I have a custom client formatting sink provider which creates its own custom client formatting sink during the configuration.

I placed my custom sink provider in the configuration file just before soap formatter provider so that it would be created before soap formatter provider. When I test it, every thing works fine as it was intended and I can break into my custom client formatter sink during debugging.

Here is the code for SyncProcessMessage for my custom formatter sink.

public IMessage SyncProcessMessage(IMessage msg)
{
    IMessage retMsg = ((IMessageSink) _nextSink).SyncProcessMessage(msg);
    return retMsg;
}

I simply delegate the work to next sink in the sink chain.

Here is my question:

I want to make an asynchronous call on the next sink in the chain instead of sync call. The method to be used is SoapClientFormatterSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink) which returns IMessageCtrl which only method is called Cancel.

Since this is async call, the call will return immediately. How do I retrieve the reply message? Obviously I have to wait until I get the reply message. But where do I need to look for the message?

BTW: SoapClientFormatterSink.AsyncProcessMessage returns null.

Answer

You have to create another class which implement IMessage sink and which will take the response from the call as soon as it's available:

public class SomeReplySink: IMessageSink 
{

  IMessageSink _next;

  public SomeReplySink(IMessageSink next) 
  {
     _next = next;
  }

  public IMessageSink NextSink 
  {
    get { return _next; }
  }   

  public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) 
  {
     // nothing to do, response will be synchronous (i.e. the handling of the 
     // asynchronous response will itself be handled synchronously)
  }

  public IMessage SyncProcessMessage(IMessage msg) 
  {
     // [HERE YOU CAN CHANGE THE REPLY WHENEVER IT ARRIVES!] 
     System.Console.WriteLine("REPLY:SyncProcessMessage()");

     // pass it on to the next reply sink
     return _next.SyncProcessMessage(msg);
   }
}

Then you can do something like the following in your main IMessageSink (where you already implemented SyncProcessMessage() as described in the question):

Class YourSink: ...
{
   // ... rest of implementation ...

   public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) { 
      //[HERE YOU CAN CHANGE THE ORIGINATING MESSAGE]
      System.Console.WriteLine("CALL: AsyncProcessMessage()");
      return _nextMsgSink.AsyncProcessMessage(msg,new SomeReplySink (replySink));
   }
   
}

The line marked in blue in the following code-fragment creates the new reply sink (SomeReplySink) which will afterwards forward the call to the replySink object.

You can then use a config file like the following to handle async requests as well:

<configuration>
  <system.runtime.remoting>
    <application>
      <channels> 
        <channel ref="http">
          <clientProviders>
            <provider type="Somewhere.YourSink, SomeAssembly" />
            <formatter ref="soap" />
          </clientProviders>
        </channel>
      </channels>

      <!-- rest of the configfile -->
    </application>
  </system.runtime.remoting>
</configuration>





 

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