The Journey of the Lunch Launcher: Part 4 - Sending messages

Part 1 - The origins of the 'lunch launcher'
Part 2 - MEDC 2007
Part 3 - Managing the Transport

Last time, I talked about how the Lunch Launcher manages the transport objects used to communicate via Store and Forward Messaging on the .NET Compact Framework.  Today, I'm going to discuss how messages are sent.

As with all entries in this series, please note that the following disclaimer covers all examples contained herein.
//-----------------------------------------------------------------------//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A//PARTICULAR PURPOSE.//-----------------------------------------------------------------------
MEDC 2007
When preparing for MEDC 2007, I wrote the code mostly to be functional and illustrative.  I was not as concerned about optimizations.  The example below comes directly from the MEDC 2007 demo project.  In a little bit, we will see how it has changed since then.  In both versions of the project, the SendMessage method is a member of the TransportObjects class that I introduced in part 3.
/// <summary>/// Send a message/// </summary>/// <param name="recipients">/// Collection of recipient email addresses/// </param>/// <param name="messageBody">/// The message contents/// </param>public void SendMessage(List<String> recipients,                        Object messageBody){    // create the serializer        LunchObjectSerializer serializer =         new LunchObjectSerializer(messageBody.GetType());

    // create the output channel
    IOutputChannel outputChannel = CreateOutputChannel(recipients);
    outputChannel.Open();
           
    // create the message
    Message msg = Message.CreateMessage(
                           // use the channel's default version
                           outputChannel.GetProperty<MessageVersion>(),
                           "urn:Microsoft.ServiceModel.Samples.LunchLauncher",
                           messageBody,
                           serializer);

    // send the message
    outputChannel.Send(msg);  
           
    // close the output channel
    outputChannel.Close();
    outputChannel = null;  

How does it work?  SendMessage is called with a collection of email addresses corresponding to the user's buddies (managed by the lunch launcher engine) and the payload for the message.

The first thing SendMessage does is to construct a LunchObjectSerializer (an implementation of XmlObjectSerializer) and tells it what type of object it will be serializing (via messageBody.GetType()).  Next, SendMessage creates and opens the channel used to send the message to the recipients. 

Once we have the output channel, the Message object can be created from the message body and serializer.  The message is then sent an the output channel is closed (it is no longer needed).

That's how all messages are sent in the Lunch Launcher.  There is no custom code for any of the message types. 

Current version
Since coming back to Redmond and spending some time on the Lunch Launcher project, I have made a change to how messages are sent  Here's how the SendMessage method looks today.
/// <summary>/// Send a message/// </summary>/// <param name="recipients">/// Collection of recipient email addresses/// </param>/// <param name="messageBody">/// The message contents/// </param>/// <param name="serializer">/// The serializer used to encode the message for sending/// </param>public void SendMessage(List<String> recipients,                        Object messageBody,                        LunchObjectSerializer serializer) {    // create the output channel    IOutputChannel outputChannel = CreateOutputChannel(recipients);            outputChannel.Open();                // create the message    Message msg = Message.CreateMessage(                           // use the channel's default version                           outputChannel.GetProperty<MessageVersion>(),                           "urn:Microsoft.ServiceModel.Samples.LunchLauncher",                           messageBody,                           serializer);

    // send the message
    outputChannel.Send(msg);  
           
    // close the output channel
    outputChannel.Close();
    outputChannel = null;  

Did you spot the change?  SendMessage is now called with a third parameter -- the LunchObjectSerializer.  The LunchObjectSerializer had previously created within SendMessage.  This was done to optimize memory use and performance.

Every time an XmlSerializer is created for an object, that object must be examined via Reflection to determine how to convert its contents into XML.  As has been discussed on many weblogs and conference presentations, Reflection is expensive.  By reducing the number of times the LunchObjectSerializer object is created, the memory footprint is lower and performance improves (less reflection, fewer garbage collections).  In fact, I was able to get the number of serializers down to exactly three for the entire application.  The same serializers are used for sending and receiving messages.

In the MEDC version, there was a performance penalty for being popular (sending more messages).  In the current implementation, the popularity penalty has been eliminated. :)

Next time, we'll look at how messages are received and processed.

Take care,
-- DK

Disclaimer(s):
This posting is provided "AS IS" with no warranties, and confers no rights.
The information contained within this post is in relation to beta software. Any and all details are subject to change.