Share via


Occasionally Connected Clients – Queuing Messages

This blog includes:

  • Why we are doing this?
  • Getting started
    • Setup on Web Portal
      • ServiceName, IssuerName, IssuerSecret
    • Install c:\Program Files\Windows Azure platform AppFabric SDK
    • Visual Studio 2010
    • Source Code
  • Big picture
  • Sample code run
  • The Code

Source Code

https://brunoblogfiles.com/zips/WeatherBillboard.zip

Why Are We Doing This?

One of the difficult problems to solve for developers is dealing with client computers that are not always connected. Although connectivity and reliability continues to improve, there are many scenarios where we want a “buffer in the cloud.”

These buffers waits in the cloud for the client to connect. At that point, when a client connects, message can finally be read by the client. These message can expire and don’t necessarily need to stick around forever. Afterall, some message lose their relevance with the passage of time, like weather, for example.

There is a caveat, however – Fault Tolerance

Because message buffer contents are stored in active memory, there are no strong fault tolerance or reliability guarantees. If the server hosting a message buffer crashes, you may lose messages. In the event of a server crash, you will not necessarily lose the buffer itself: knowledge of the buffer, including policy settings, is distributed across multiple servers and may be recovered. However, any messages in your buffer at the time of the crash will be lost. Therefore, if you are designing an application that needs a high degree of message reliability, it is recommended that you provide for message redundancy and recovery through other means.

Differences from WCF

It is important to realize that a Service Bus message buffer application is not designed like a WCF application: there is no host, or explicitly defined channel, or strong service/client paradigm. Instead, an application simply calls CreateMessageBuffer on an endpoint, and then either sends messages to it, or pulls messages from it. In addition, as mentioned above, the message buffer can be managed and accessed by non-Windows applications through REST only.

Getting Started

In order to work with the code and a live example, there are a few things you need to do:

Big Picture

To make things more concrete, envision this scenario. Consider the weather billboards below. The weather billboards are occasionally disconnected and therefore need a way to have message waiting in a buffer in the AppFabric Service Bus.

In the diagram below the Weather Billboard User is interested in securely reading  waiting messages in the cloud. The user might be on a wireless network, going through a router and firewall.

image

image

Figure 1 : Example of Listeners – the Weather Billboard

Let’s take a look at a sample implementation for the Weather Billboards. Another way to think about it is who is the “publisher” and who is the “consumer?” So the point of this blog is to walk you through the mechanics of doing this.

I want to demonstrate how to use the Windows Azure platform AppFabric Service Bus and its message buffer feature.

The Weather Billboard application creates the message buffer and then retrieves messages from it that are sent by the Weather Station. Creating a message buffer requires the credentials for the endpoint, the message buffer URI, and the message buffer policy. The Weather Billboard creates these prerequisite objects.

Sample code run

Step 1 – Run the WeatherStation

    • Run the WeatherStation.exe application
    • Click on the top button to connect
    • Type in some weather conditions to send out
    • Click “Send Weather Conditions”
  • You can send more than one. They get queued up.

image

Step 2 – Close Weather Station

  • Close the WeatherStation.exe application
  • At this point both the producer and consumer are both disconnected

Step 3 – Start Weather Billboard

  • Click on the top button to connect
  • Click “Read Weather Conditions”
  • You can read more than one. They have been queued up

image

The code – Source Available Above

Note the two projects here that have both a Service Bus and User Interface code component. CredentialInfo.cs holds all the Shared Secret keys that you got from the web portal.

image

Code PrintOut – WeatherBillboard::CredentialInfo.cs

You must now go to the web portal. This is the screen you are looking for:

 

image

Go to the web portal for:

serviceNamespace

IssuerName

IssuerSecret

Note: The key line is line 10, where you need to choose the right service name. Lines 11 and 12 also need to be filled out using the information in the immediate screen above.

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace WeatherBillboard
  7. {
  8.     class CredentialInfo
  9.     {
  10.         private string serviceNamespace = "WeatherCentralService";
  11.         private string issuerName = "owner";
  12.         private string issuerSecret = "";
  13.  
  14.         public string ServiceNamespace
  15.         {
  16.             get { return serviceNamespace; }
  17.             set { serviceNamespace = value; }
  18.         }
  19.  
  20.         public string IssuerName
  21.         {
  22.             get { return issuerName; }
  23.             set { issuerName = value; }
  24.         }
  25.  
  26.         public string IssuerSecret
  27.         {
  28.             get { return issuerSecret; }
  29.             set { issuerSecret = value; }
  30.         }
  31.  
  32.  
  33.     }
  34. }

Code PrintOut – WeatherBillboard::MessageBuffer.cs

Code Snippet

  1. using System;
  2.  
  3. using System.Text;
  4. using Microsoft.ServiceBus;
  5. using System.ServiceModel.Channels;
  6.  
  7. namespace WeatherBillboard
  8. {
  9.     public class MyMessageBuffer :  IDisposable
  10.     {
  11.         private MessageBufferClient client;
  12.         private MessageBufferPolicy policy;
  13.         private TransportClientEndpointBehavior credential;
  14.         private Uri uri;
  15.         private CredentialInfo credentials = new CredentialInfo();
  16.         private bool _disposed;
  17.  
  18.  
  19.         public bool SetupSecurity()
  20.         {
  21.             this.policy = new MessageBufferPolicy();
  22.             this.policy.Authorization = AuthorizationPolicy.Required;
  23.             this.policy.MaxMessageCount = 10;
  24.             this.policy.ExpiresAfter = TimeSpan.FromMinutes(5); // messages in the message buffer expire after 5 mins
  25.             this.policy.TransportProtection = TransportProtectionPolicy.AllPaths;
  26.             
  27.             // create the credentials object for the endpoint
  28.             this.credential = new TransportClientEndpointBehavior();
  29.             this.credential.CredentialType = TransportClientCredentialType.SharedSecret;
  30.             this.credential.Credentials.SharedSecret.IssuerName = credentials.IssuerName;
  31.             this.credential.Credentials.SharedSecret.IssuerSecret = credentials.IssuerSecret;
  32.             return true;
  33.         }
  34.         public void CreateServiceUri()
  35.         {
  36.             // create the URI for the message buffer
  37.             this.uri = ServiceBusEnvironment.CreateServiceUri("https", credentials.ServiceNamespace, "MessageBuffer");
  38.         }
  39.         public void Dispose()
  40.         {
  41.             Dispose(true);
  42.             GC.SuppressFinalize(this);      
  43.         }
  44.         protected virtual void Dispose(bool disposing)
  45.         {
  46.             // If you need thread safety, use a lock around these
  47.             // operations, as well as in your methods that use the resource.
  48.             if (!_disposed)
  49.             {
  50.                 if (disposing)
  51.                 {
  52.                     // Nothing here right now. All clean !
  53.                 }
  54.  
  55.             // Indicate that the instance has been disposed.
  56.             //_resource = null;
  57.             _disposed = true;   
  58.             }
  59.         }
  60.         public string GetNextMessage()
  61.         {
  62.             Message message;
  63.             string content;
  64.  
  65.             // Retrieve a message (destructive read)
  66.             message = client.Retrieve();
  67.             content = message.GetBody<string>();
  68.             message.Close();
  69.             return content;
  70.  
  71.         }
  72.         public void CreateMessageBuffer()
  73.         {
  74.             this.client = MessageBufferClient.CreateMessageBuffer(this.credential, this.uri, this.policy);
  75.         }
  76.     }
  77. }

Code PrintOut – WeatherBillboard::MainWindow.xaml

image

Code Snippet

  1. <Window x:Class="WeatherBillboard.MainWindow"
  2.         xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  4.         Title="MainWindow" Height="350" Width="525">
  5.     <Grid>
  6.         <Button Content="Connect to Service Bus" Height="56" HorizontalAlignment="Left" Margin="41,27,0,0" Name="button1" VerticalAlignment="Top" Width="176" Click="button1_Click" />
  7.         <Button Content="Read Weather Conditions" Height="56" HorizontalAlignment="Left" Margin="41,97,0,0" Name="button2" VerticalAlignment="Top" Width="176" Click="button2_Click" />
  8.         <TextBlock Height="126" HorizontalAlignment="Left" Margin="42,168,0,0" Name="textBlock1" VerticalAlignment="Top" Width="440" />
  9.     </Grid>
  10. </Window>

Code PrintOut – WeatherBillboard::MainWindow.xaml.cs

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. using System.Drawing;
  15. using System.IO;
  16. using System.Net;
  17.  
  18. namespace WeatherBillboard
  19. {
  20.     public partial class MainWindow : Window
  21.     {
  22.         Window mainWindow = new Window();
  23.         MyMessageBuffer message_buffer = new MyMessageBuffer();
  24.  
  25.         public MainWindow()
  26.         {
  27.             InitializeComponent();
  28.  
  29.         }
  30.         private void button1_Click(object sender, RoutedEventArgs e)
  31.         {
  32.  
  33.             message_buffer.SetupSecurity();
  34.             message_buffer.CreateServiceUri();
  35.             message_buffer.CreateMessageBuffer();
  36.             this.Title = "Weather Billboard is connected...";
  37.         }
  38.         private void button2_Click(object sender, RoutedEventArgs e)
  39.         {
  40.             string message = message_buffer.GetNextMessage();
  41.             this.textBlock1.FontSize = 32;              
  42.             this.textBlock1.Inlines.Clear();
  43.             this.textBlock1.Inlines.Add("The Weather Station sent us ");
  44.             this.textBlock1.Inlines.Add(new Bold(new Italic(new Run(message))));
  45.             this.textBlock1.TextWrapping = TextWrapping.Wrap;
  46.         }
  47.     }
  48. }

Code PrintOut – WeatherStation::CredentialInfo.cs

Go to the web portal for:

  • serviceNamespace
  • IssuerName
  • IssuerSecret

It is the same as WeatherBillboard::CredentialInfo.cs

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5.  
  6. namespace WeatherStation
  7. {
  8.     class CredentialInfo
  9.     {
  10.         private string serviceNamespace = "WeatherCentralService";
  11.         private string issuerName = "owner";
  12.         private string issuerSecret = "";
  13.  
  14.         public string ServiceNamespace
  15.         {
  16.             get { return serviceNamespace; }
  17.             set { serviceNamespace = value; }
  18.         }
  19.  
  20.         public string IssuerName
  21.         {
  22.             get { return issuerName; }
  23.             set { issuerName = value; }
  24.         }
  25.  
  26.         public string IssuerSecret
  27.         {
  28.             get { return issuerSecret; }
  29.             set { issuerSecret = value; }
  30.         }
  31.  
  32.  
  33.     }
  34. }

Code PrintOut – WeatherStation::MessageBuffer.cs

Code Snippet

  1. using System;
  2.  
  3. using System.Text;
  4. using Microsoft.ServiceBus;
  5. using System.ServiceModel.Channels;
  6.  
  7. namespace WeatherStation
  8. {
  9.     public class MyMessageBuffer :  IDisposable
  10.     {
  11.         private MessageBufferClient client;
  12.         private MessageBufferPolicy policy;
  13.         private TransportClientEndpointBehavior credential;
  14.         private Uri uri;
  15.         private CredentialInfo credentials = new CredentialInfo();
  16.         private bool _disposed;
  17.  
  18.  
  19.         public bool SetupSecurity()
  20.         {
  21.             this.policy = new MessageBufferPolicy();
  22.             this.policy.Authorization = AuthorizationPolicy.Required;
  23.             this.policy.MaxMessageCount = 10;
  24.             this.policy.ExpiresAfter = TimeSpan.FromMinutes(5); // messages in the message buffer expire after 5 mins
  25.             this.policy.TransportProtection = TransportProtectionPolicy.AllPaths;
  26.             
  27.             // create the credentials object for the endpoint
  28.             this.credential = new TransportClientEndpointBehavior();
  29.             this.credential.CredentialType = TransportClientCredentialType.SharedSecret;
  30.             this.credential.Credentials.SharedSecret.IssuerName = credentials.IssuerName;
  31.             this.credential.Credentials.SharedSecret.IssuerSecret = credentials.IssuerSecret;
  32.             return true;
  33.         }
  34.         public void CreateServiceUri()
  35.         {
  36.             // create the URI for the message buffer
  37.             this.uri = ServiceBusEnvironment.CreateServiceUri("https", credentials.ServiceNamespace, "MessageBuffer");
  38.         }
  39.         public void Dispose()
  40.         {
  41.             Dispose(true);
  42.  
  43.             // Use SupressFinalize in case a subclass
  44.             // of this type implements a finalizer.
  45.             GC.SuppressFinalize(this);      
  46.         }
  47.         protected virtual void Dispose(bool disposing)
  48.         {
  49.             // If you need thread safety, use a lock around these
  50.             // operations, as well as in your methods that use the resource.
  51.             if (!_disposed)
  52.             {
  53.                 if (disposing)
  54.                 {
  55.                     // Nothing coded for cleanup yet
  56.                 }
  57.  
  58.             // Indicate that the instance has been disposed.
  59.             //_resource = null;
  60.             _disposed = true;   
  61.             }
  62.         }
  63.         public string GetNextMessage()
  64.         {
  65.             Message message;
  66.             string content;
  67.  
  68.             // Retrieve a message (destructive read)
  69.             message = client.Retrieve();
  70.             content = message.GetBody<string>();
  71.             message.Close();
  72.             return content;
  73.  
  74.         }
  75.         public bool SendMessage(string message)
  76.         {
  77.             MessageVersion messageVersion = MessageVersion.Soap12WSAddressing10;
  78.             string messageAction = "urn:Message";
  79.             client.Send(Message.CreateMessage(messageVersion, messageAction, message));
  80.             return true;
  81.         }
  82.         public void CreateMessageBuffer()
  83.         {
  84.             this.client = MessageBufferClient.CreateMessageBuffer(this.credential, this.uri, this.policy);
  85.         }
  86.     }
  87. }

Code PrintOut – WeatherStation::MainWindow.xaml

image

Code Snippet

  1. <Window x:Class="WeatherStation.MainWindow"
  2.         xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  4.         Title="Weather Station" Height="350" Width="525">
  5.     <Grid>
  6.         <Button Content="Connect to Service Bus" Height="56" HorizontalAlignment="Left" Margin="41,27,0,0" Name="button1" VerticalAlignment="Top" Width="176" Click="button1_Click" />
  7.         <Button Content="Send Weather Conditions" Height="56" HorizontalAlignment="Left" Margin="41,97,0,0" Name="button2" VerticalAlignment="Top" Width="176" Click="button2_Click" />
  8.         <TextBox Height="72" HorizontalAlignment="Left" Margin="44,196,0,0" Name="textBox1" VerticalAlignment="Top" Width="277" TextWrapping="WrapWithOverflow" VerticalScrollBarVisibility="Auto" />
  9.     </Grid>
  10. </Window>

Code PrintOut – WeatherStation::MainWindow.xaml.cs

Code Snippet

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Data;
  8. using System.Windows.Documents;
  9. using System.Windows.Input;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Windows.Navigation;
  13. using System.Windows.Shapes;
  14. using System.ServiceModel.Channels;
  15.  
  16. namespace WeatherStation
  17. {
  18.     /// <summary>
  19.     /// Interaction logic for MainWindow.xaml
  20.     /// </summary>
  21.     public partial class MainWindow : Window
  22.     {
  23.  
  24.         MyMessageBuffer message_buffer = new MyMessageBuffer();
  25.         public MainWindow()
  26.         {
  27.             InitializeComponent();
  28.         }
  29.  
  30.         private void button1_Click(object sender, RoutedEventArgs e)
  31.         {
  32.  
  33.             message_buffer.SetupSecurity();
  34.             message_buffer.CreateServiceUri();
  35.             message_buffer.CreateMessageBuffer();
  36.             this.Title = "Weather Station just connected...";
  37.         }
  38.  
  39.         private void button2_Click(object sender, RoutedEventArgs e)
  40.         {
  41.             message_buffer.SendMessage(this.textBox1.Text);
  42.             this.Title = "Weather Station just sent " + this.textBox1.Text;
  43.         }
  44.     }
  45. }

 

References

image

This part is important. Make sure Microsoft.ServiceBus points to

C:\Program Files\Windows Azure platform AppFabric SDK\V1.0\Assemblies\Microsoft.ServiceBus.dll

Some information about reading from message buffers

When you read a message you can do it two ways:

Method 1 : A destructive read

  • Automatically deletes the message from the buffer

Method 2 : Peek/Lock

  • When you choose to peek/lock a message, a copy of the message is sent to the client. Careful about the lock, though.
  • The message is held temporarily by the message buffer, but “locked” so that no one else can retrieve it.

*Note*

  • During this time, you or other clients can still pull other messages from the buffer.

Automatic Lock Release if Timeout

  • If the client does not explicitly instruct the message buffer to delete the locked message before the lock timeout expires, the message buffer releases the lock on the message

More on this later. I will add some more code commentary. But you have enough here to implement your own. In my next blog entry, I will get the Weather Station to read data from the National Weather Service.