Click here to Skip to main content
11,648,911 members (81,174 online)
Click here to Skip to main content

Using Windows Azure Service Bus Messaging.

, 1 Nov 2011 CPOL 76.5K 1.4K 47
Rate this:
Please Sign up or sign in to vote.
This article describes consuming Windows Azure Service Bus by WCF and WF Technologies.







The Windows Azure AppFabric Service Bus September 2011 (version 1.5)  release introduces enhancements to the Service Bus such as "brokered" messaging capabilities, through namespace entities represented by queues, topics and subscriptions. The Brokered Messaging infrastructure enables to build an Event-driven distributed Service Oriented Architecture, Distributed Asynchronous Cloud Notifications and Intra-Application Messaging. Basically, it can be useful anywhere where  a loosely decouple messaging is required such as Queuing and Publish-Subscribe messaging across both on-promises and cloud targets.

From the abstraction point of the view, the Azure Service Bus represents a logical connectivity between the event sources and their consumers using a loosely decouple model. The consumers need to subscribe their interest to the Service Bus in prior of receiving a specific event interest. This metadata (subscriptions) represents a logical connectivity for event interest; they are stored on the cloud a managed by tools and/or specific client applications.

The following picture shows an Azure Service Bus abstraction:



The above picture shows very high abstractions to hide an AppFabric infrastructure, entities and etc. to show the basic model of the Azure Service Bus. Basically, there is a Publisher of the event interest, Subscriber for receiving this interest and Administrator to assign a logical connectivity between the Publisher and Subscriber in the secure manner. The Service Bus is highly available, scalable, multi-tenant service for connecting clients such as Publishers, Subscribers, Admin, etc. The model of the logical connectivity is stored in the SQL Azure. Currently, the Azure Service Bus model supports Namespace entities such as Queue, Topic and Subscription.

The following picture shows a screenshot of the WindowsAzurePlatform Service Bus Admin Tool:


 As you can see, the Subscription-1 account has one Service Bus Namespace scope named as rk2011. As I mentioned earlier, the Service Bus is multi-tenant model, where Namespaces are logical isolated entities, in other words, Publishers, Subscribers and admin tools are visible each to other based on the Namespace scope.

The following picture shows next drill-down level of the Service Bus abstraction:


Basically, the above picture shows service-client architecture. The current release version of the Azure SDK 1.5 includes many "horse-worker" classes and methods to simplify access to the Service Bus Service. The Brokered Messaging feature on the Azure Service Bus is built on the top of the WCF paradigm using full-duplex connection-oriented sessions between the Sender and Receiver (Listener) with a bi-directional communication (Microsoft.ServiceBus.Messaging.SBmp internal classes) From the application (business) layer, the messaging between Sender and Receiver is One-way supporting unicast and multicast datagram distribution.

This article is focusing on consuming Azure Service Bus by WCF and WF Technologies. I will discuss how it can be used in the transparent manner as part of the Logical Model Connectivity. In the References, you can find more details about the Service Bus entities and their programming using an API methods and RESTful  from the Microsoft.ServiceBus.Messaging Namespace. I strong recommend to read Service Bus Brokered Messaging Performance - Best Practices Guide.

Let's describe the major entities of the Azure Service Bus focusing on the WCF/WF usage.

Brokered Message

The Brokered Message (BM) is a fundamental entity in the Service Bus Messaging infrastructure. Its conceptual design is similar to WCF Message. The BM is holding sys properties such as Label, TimeToLive, CorrelationID, etc. for message control flow and userapplication specific properties and of course the body (message payload). The sysand userproperties are packaged to the bag under the name BrokeredMessageProperty (BMP)  The important thing is that this BMP bag can flow between the Business-To-Business layers. The following picture shows a WCF Message for ServiceBus Messaging:  

The BrokeredMessagePropertybag is attached to the WCF Message via its Properties collection. Having the BMP out of the message body allows us to use it without serializing/deserializing the business payload by Service Bus infrastructure. Note, that the name of the key in the collection is BrokeredMessageProperty.

Adding BMP into the WCF Message Properties collection is very straight forward like it is shown in the following code snippet:

using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
  var bmp = new BrokeredMessageProperty() { Label = "HelloCloud" };
  bmp.Properties.Add("abcd", (long)12345);
  bmp.Properties.Add("id", Guid.NewGuid());
  OperationContext.Current.OutgoingMessageProperties.Add(BrokeredMessageProperty.Name, bmp);


The above example is for adding the BMP in an imperatively way using an OperationContextScopefor channel (proxy). The following picture shows this process graphically. The point is that the Sender/Publisher is a producer of the BrokeredMessageto the Azure Service Bus. In other words, the WCF Message + BMP are converted into the BrokeredMessage. This task is implemented by custom channel for NetMessagingTransportincluded in the Azure SDK 1.5.

The behind the above picture is implementation of the ServiceBusOutputChannel, where the wcfMessage is converted to BrokeredMessage and sent it by SbmpMessageSender to the Service Bus channel. The following code snippet from .NetReflector shows this logic in the Microsoft.ServiceBus.Messaging.Channels.ServiceBusOutputChannel:

public SendAsyncResult(ServiceBusOutputChannel outputChannel, Message message, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state)
  this.outputChannel = outputChannel;
  BrokeredMessage message2 = null;
    message2 = outputChannel.ConvertToBrokerMessage(message, out this.bufferToReturn);
    IAsyncResult result = outputChannel.MessageSender.BeginSend(
      new BrokeredMessage[] { message2 }, 
    if (base.SyncContinue(result))
  catch (MessagingException exception)
    // ...
    throw FxTrace.Exception.AsError(exception2);
  catch (Exception)
    // ...

That's great. But do I need to modify my existing WCF Sender/Publisher for Azure Service Bus Messaging?

Well, it is not necessary, this article gives you a solution for adding a BrokeredMessagePropertydeclaratively using a config file and custom EndpointBehavior. The following code snippet shows this feature in the code:

  new RKiss.Activities.Azure.Messaging.MessagePropertyActionEndpointBehavior()
     Expression = "SET sys.Label='HelloCloud'; SET abcd=12345; SET id=newid()"

As you can see, this custom endpoint behavior implements an Action feature based on the SqlExpression. The above example will setup a message label (sys property) and couple user properties such as abcdand idwith a new Guid value. Note, that the BMPis important for message processing, for example, based on the user properties the message can be forwarded to the subscriber, etc. More details can be found later in the usage examples of this article.

Queue Entity

The Queue Entity represents a logical connectivity between the producer and consumer ends. It's point to point pattern connectivity. The concept is similar to the on-promises MSMQ Technology. The following picture shows this basic concept:


The Sender sending a BrokeredMessageto the specific queue from where the message can be pulled by its Receiver. There are advanced messaging features such as schedule time, time to live, session capability, etc. More details can be found in the References. Basically, this messaging can be used for migrating NetMsmqBindingconfiguration to the NetMessagingBinding(Azure Service Bus) in the transparent manner, just by updating the config file. In some cases, during this migration we can use better pattern, for example, using SchedulerEnqueueTimeUtcproperty allows sending a message to the queue in the specific time, which can be useful for retry mechanisms.

As the above picture shows, there are multiple ReceiverN for the same queue. In this scenario, the message will balance between the receivers in round-robin manner, which is perfect use for IIS/WAS/WebRole hosting. Note, the receiver service on the hosting environment must have Auto-Start enabled.

The following code snippet shows example of receiver configuration on the queue 'Queue1':

That's great. As you can see, the above configuration will "plug-in" WCF Service to receiving a message from the Azure Service Bus Queue. All the magic work is done in the WCF paradigm using its extension such as netMessagingBindingand transportClientEndpointBehavior. This capability allows building a logical connectivity stored in the Repository and physically deployed to the target based on the deployment model.


Topic Entity

The Topic Entity represents a logical connectivity for event interests in the specific Namespace. This is a Publish/Subscribe (Pub/Sub) pattern connectivity, where sources publish an event interest on the logical channel known as Topicand consumers will receive it based on their interest. This connectivity pattern enables us to build an event-driven distributed architecture where producers and consumers are loosely decoupled and disconnectable.

The following picture shows the topic-based messaging concept to see a fundamental difference from the previous, queue-based messaging: 



As you can see, the Publisher sends a BrokeredMessageto the Namespace/Topic virtual channel without any knowledge of its consumers in the loosely decouple manner. Publishers can decide on a lifetime of the sent message such as TimeToLive, SchedulerEnquueTime, etc. The application can mark the message with a source event interest to identify a specific event. In the loosely decouple manner, there are Subscribers registered to the Topic which represents a consumers of the event interest. Registration process is known as subscribing interest on topic.

Subscription Entity

In the Topic Model, this abstraction is represented by Subscription. Every Subscriber must have a Subscription. This entity represents a logical connectivity between the Publisher and Subscriber on the specific Topic channel. Based on the Subscription, the Subscriber gives an interest for Topic to receive a message (described by RuleDescription) and some information for message control flow in the case of exceptions, batch operation, etc. 

As I mention earlier, to receive a copy of published message, Subscriber needs to subscribe its subscription to the specific Topic. The Subscriptions can be empty, default with one RuleDescriptionor with multiple RuleDescriptions.

The following picture snippet shows this abstraction, where Subscription is a collection of the RuleDescriptionentities:

To obtain the copy of the BrokeredMessage from the Topic channel, the RuleDescriptionwithin the Subscription must be succeeded. In other words, based on the Subscription Filter(s), the message copy is delivered to the Subscriber. The RuleDescriptionin the Azure Service Bus Messaging has built-in two features, such as Filter and Action. Both are based on SqlExpression and have been implemented with certain limitation to the BrokeredMessageentity, for example: scope of the property can be sys and/or user.

From the Topic point of the view, the message is delivered only if we have valid subscription during the message lifetime. Basically, if we don't have any valid Subscribers to the Topic, messages will live there based on their TimeToLiveproperty. In other hand, the Topic can have many (based on the Quotas such as 2000 subscriptions per Topic) empty subscriptions, default subscriptions - TrueFilter(one default RuleDescription) or subscription with multiple RuleDescriptions.

As I motioned earlier, the Topic channel is loosely decouple model, where Subscribers and Subscriptions are independed of each other. In other words, Subscription can be created and registered by Subscriber or any application component and/or management portal site. The Subscription can be static or dynamicly created on the fly.

Keep in mind, when Subscription is unregistered (deleted) from the Topic, its active Subscriber is disconnected, and it will be required to reconnected in order to renew the subscription. In the case of the dynamic subscription, when subscriber will create its own subscription, it is not a problem, but for static subscription needs to be handle it.

Empty Subscription vs. Default Subscription

As we know, the Subscriber needs to subscribe an interest to the specific Topic. But there is a special case when the subscriber (or management) doesn't know in advance of this interest. Therefore, it is beneficial to use an Empty Subscription, which will allow creating the Subscriber for Topic and its Listener on the Empty Subscription.

When Subscription is created automatically, it is created for one (default) RuleDescription. If there is no filter expression (default constructor), the TrueFilteris applied as a Default Subscription. In this case, every published message delivers its copy to this Subscriber. Keep in mind this feature when the multicast messaging is required. 

By deleting the default RuleDescriptionin the Default Subscription, we can obtain an Empty Subscription without any glitches on the active Subscriber. Deleting RuleDescription in the Subscription can be done by its Subscriber (one time message receiver) or other components.

In the opposite process, the RuleDescriptioncan be added into the Subscription. Note, that each Filter in the RuleDescriptionmust match for message (copy) delivery to its Subscriber.


The BrokeredMessage received by Topic channel is flowing via each Subscription for checking its interest. This interest is declared by the Filter Entity. The Service Bus Messaging has built-in few filters such as TrueFilter, FalseFilter, CorrelationFilter and SqlFilter for generic SQL92 Expression. When the filter match is true, the RuleDescription offers to execute its Action. The default action is EmtyRuleAction and for custom action, SqlRuleAction can be used using the SQL92 expression.

The scope of the filter and action is BrokeredMessage entity. The SqlExpression supports only two scopes of the BrokeredMessage such as its properties (scope name is sys) and the user scope (default scope) declared in the BrokeredMessage.Properties collection.

Filter example: "sys.Label='Order" AND TicketID=12345"

Action example: "SET sys.Label='Order'; SET abcd=12345; REMOVE TicketID; SET flag=TRUE"


Balancing vs. Multicasting (Multiple Subscriptions)

In the Queuing, we saw the by sharing a queue entity we can balance message between queue receivers in the round-robin manner. We have the same feature at Subscription, when the Subscribers are using the same Subscription. That's fine and very useful for load-balancing purposes. But wait a moment, what will happen when Subscription will have the same Filter expression? 

Well, we can get a new pattern connectivity such as multicasting. The following picture shows these two scenarios:


and their abstraction is shown here:



Basically, we can say, that "sharing" subscriptions is for balancing and "sharing" filters for message multicasting. Note, that "sharing" is used for logical explanation. I would be nice to have a Topic Model that supports referencing entities and sharing them in the Repository, but current release doesn't support it.


Addressing Queue, Topic and Subscription

The following are examples of addressing Queue, Topic and Subscription in the connected Namespace:

Addressing can also use a branching structure, for example:/myTopics/myTopic, etc. Usage of addressing can be see in the following configuration example for receiver, publisher and subscriber:

It is a straightforward standard endpoint configuration and the interesting point is the subscriber endpoint. As you can see, the base address is for addressing Topic entity and the listenUriis addressing for its subscription. Each endpoint must have a behaviorConfigurationfor credentials.

That's great. We can create Namespaces, Topics and Subscriptions in the Windows Azure Platform for our subscription. From the business model point of the view, we can look at on the Service Bus like abstraction of the connectivity, where business entities are logically connected and driven by the metadata. We can consider Service Bus such as Namespace, Queue, Topic and Subscriptions (NQTS) as part of this metadata as well. In the logical model, we can declare a logical subscription without knowledge of the physical topology of the Pub/Sub model. Basically, the Subscriber interested in the event (message) in the business model can be decomposited into multiple topics, etc. We can help our business model by declaring NQTS for public and private scope. However, our logical business model stored in the Repository will need to be physical deployed to the target and the deployment model will need a mapping process for specific physical entities of the target.

To end this thought, the current version of the Azure Service Bus Messaging doesn't support "wildcard" feature for subscription or publisher for multiple topics. In the current version, we can consider each subscription as tightly coupled with a specific one Topic. It is the same Publisher side, when on event interest is distributed only for specific Topic, not across multiple topics. It will be nice to have support like subscription for multiple topics - wildcard subscription, which will simplify our mapping from the business model.

However, we can build (on top of the fundamental Service Bus Entities) advanced hierarchy such as "wildcard subscription", publishing over multiple topics, namespaces, creating public and internal gateways, bridges, etc. The concept is very simple, subscribing interest to the specific topic and distributing it to some other one, or multicasting an event interest for multiple topics.

In the following section I will describe this pattern scenario using a WCF RoutingService, which basically represents a Subscriber/Publisher component driven by metadata located in the config file (endpoints, routing table, filters, etc.). Note that this service has a built-in capability to update a routing table and outbound clients remotely on the fly.


WCF4 Routing Service on the Service Bus

The WCF RoutingService is a perfect solution for building a gateway and/or bridges for Service Bus. For this scenario, it can be fully transparent and declaratively configured. The RoutingServicesupports both contracts for Service Bus such as ISimplexDatagramRouterand ISimplexSessionRouter.
The following picture shows one possible example, where the event interest from one Namespace/Topic must be delivered to other Topic channel (bridge pattern) and also some "legacy" producer/consumer that wants to be part of the Service Bus in the Pub/Sub scenario (gateway pattern).


In the above example, the RoutingServicecan be configured for receiving two kinds of messages such as BrokeredMessageand Message. This is a straightforward configuration, setting an address on the Topic channel and Listener on Subscription. For "legacy" Publisher, we can use a standard addressing. That's all for inbound messages. For outbound messages  such as "legacy" Subscribers and Topic channel (2) we can setup a client endpoint with addressing based on the target (service or Topic).

Now, we need to configure a Routing Table which will be "connect"; - forward the inbound message to the specific outbound channel. For simple forwarding messages from Publishers to Subscribers ("legacy" connectivity), we can use standard built-in message filters (Action, XPath, EndpointName, etc.), but for BrokeredMessage we need a custom message filter based on BrokeredMessageProperty with capability to declaratively setup this property bag for outbound message to the Service Bus. The other option is to forward an inbound BrokeredMessage without the filtering on BMP bag, for example: EndpointName, Action, Address. etc.

OK, without any implementation details (it will be described later) the following configuration allows filtering inbound message from the Service Bus and generating BMP bag for outbound message to the Service Bus:


The messagePropertyActionis a custom endpoint behavior for message inspector to update outgoing message properties for BMP bag. The other element  is a custom MessageFilter to execute SqlExpressionon the incoming message with a BMP bag.

This is exciting, we can have a generic solution for gateway and bridge from/to Service Bus which can be very easily deployed on the cloud and used as an Azure Storage Blob for routing table - see more details about this solution in my previous article RoutingService on Azure. This article gives you a solution how we can mediate a message to/from the Service Bus using a WF Technology.

Note, that the RoutingService has a built in capability for backup message delivery, which can also be used it in our scenario.

Based on this concept described in the above example, the RoutingService can be configured for bridging messages across multiple Namespaces and Topics. The RoutingService can have multiple endpoints configured for different Topics and Subscriptions. The following picture shows this abstraction:



Another advanced feature of the RoutingService for Service Bus. As we know, the current release Service Bus Quotas limited number of subscription on the Topic. The following picture shows how we can work around this limitation:

The concept is very simple and straightforward. The RoutingService can be subscribed to the Topic and based on the FilterTable rules can forward a message to multiple clients in the multicasting manner.

One more advanced feature of the RoutingService on the Service Bus. The following picture shows subscribing a RoutingService with Subscription contains multiple RuleDescriptions. The inbound messages received by this Subscription (from each Rule) can be forwarded to the proper outbound channel based on the custom message filter for BrokeredMessageProperty bag driven by Routing (Filter) Table.



Publisher represents a sender (producer) of the event interest. In the Pub/Sub pattern, the Publisher is loosely decoupled from the consumers, therefore its publishing is addressed to the virtual channel which in the Azure Service Bus Messaging is represented by Topic. The Publisher supports only one message exchange pattern such as One-Way operation (Fire&Forget) without the SessionMode.Required, therefore the Publisher WCF channel can be implemented IOutputChannel channel only. The following example shows a generic (untyped) contract for Publisher:

public interface IGenericOneWayContract
    [OperationContract(IsOneWay = true, Action="*")]
    void Message(System.ServiceModel.Channels.Message msg);

Let's look at how we can create a Publisher for Topic. I will demonstrate it by WF Technology using a declarative way. Basically, in simple case, when the event interest can be signed statically in the BMP bag, there is no difference for proxy channel (sender), the BMP bag can be created declaratively like it has been described earlier, using the custom endpoint behavior (messagePropertyAction).  When the BMP bag is created dynamically, based on the business model, we need a mechanism how to add it to the outgoing message properties.

The following example shows adding BMP bag to the untyped message created by custom activity CreateMessage based on the Contract-First Model and then sending it by activity Send:

The above picture shows two custom activities to simplify this message mediation, the first one can be found in my article WF4 Custom activities for message mediation and the other one is part of this article and it will described in detail later on. So, these two custom activities will create a complete message for sending by Send Activity, including headers, properties, body, etc. using a full declaratively way for any element and entity.

The other way, when we want to use strong type message contract, we can use the following pattern based on the injecting a BMP bag in the message inspector. The following picture shows this case:

Again, we need some help with this extension, that's why here is a custom activity SendScopewhich is basically wrapper for SendActivity. The Message mediation for Service Bus such as adding a BMP bag to the message properties is very simple and straightforward. First step is creating this BMP bag and the second one is to assign to the Properties in the SendScope activity. This custom activity is included in this article download.

Note: The WF4 Send Activity didn't allow to add a custom endpoint behavior declaratively. There is only one way how it can be done such as explicitly setup the Send.EndpointConfigurationName property by name of the client endpoint from the config file (e.g. topic). It will be nice to have a capability for injecting a custom endpoint behavior using a custom wrapper around the Send activity in the next release WF 4.5.



AssignBMP<T> is a custom activity for creating an instance of the BrokeredMessagePropertyobject and  assigning it to the System.ServiceModel.Channels.Message.Properties or Microsoft.ServiceBus.Messaging.BrokeredMessagePropertydeclared variable.


The design and implementation of this custom activity is based on BMP class type for properties in the sys scope and one collection of the user parameters. This BMP bag is required by Service Bus infrastructure for a message control flow and additional user specific data between the producer and the consumers. The custom AssignBMP activity simplifies a message mediation process.


The Subscriber represents a receiver (consumer) end point of the BrokeredMessage. In the case of no interesting BMP in the service mediation, the Subscriber is a regular Receiver. In the other case, when the service mediation needs a BMP bag (additional business data), we need to obtain it from the custom activity OperationContextScope. This is a Receiver wrapper to inject a value of the OperationContext.Current to the workflow thread scope, which will get our BMP bag from the IncomingMessageProperties collection.

The Service Bus supports for Subscription and Queue two message exchange patters such as IInputChanneland IInputSessionChannel. Once these Service Bus entities have been declared for session (required), the Subscriber (Receiver) needs to implement a session-aware contract. The following is an example of the untyped contract for sessionful pattern:

[ServiceContract(SessionMode = SessionMode.Required)]
public interface IGenericOneWaySessionContract
    [OperationContract(IsOneWay = true, Action="*")]
    void Message(System.ServiceModel.Channels.Message msg);

The example of the Subscriber declared by xaml is shown in the following picture:

This article download contains an AzureMessagingActivityPack solution, with extensions to the BrokeredMessagePropertyand MessagePropertiesclasses. The above GetBrokeredMessagePropertymethod is one of them to hide same details.

The Subscriber can be configured in the config file. The above example shows this service Subscriber2 config section, where its endpoint has an address to the Topic channel and listener is addressed on the subscription address.


Subscriber and Multiple Publishers

The following scenario shows a mediator where we have one Subscriber and multiple Publishers. This mediator is an example of the event driven virtual storage. Mediator (StoragePublisher) has a responsibility to put a resource to the virtual storage (for example: Azure Blob Storage), publishing this event to the Topic channel and triggering a cleaner mechanism sending an event message to the queue. This message is marked with ScheduledEnqueueTimeUtcproperty which represents a resource TimeToLive. The receiver of this message will clean-up a specific resource in the Storage.

 This is an example of the pattern where consumers will pull-up a resource from the rental Storage. Instead of multicasting a heavy business payload (a resource body), the service mediator will send notification (short message) to the unknown number of consumers via the Topic channel.


The following picture shows a BMP bag:

For event-driven storage demonstration, a custom activity Microsoft.Activities.Azure.Storage.PutBlob is used. As you can see, the design is very straightforward using custom activities for putting a resource to Azure Storage and publishing events to the Azure Service Bus Topic. Note that this process is not under TransactionScope like we can have on promises environment SQL/MSMQ and it should be covered by some watchdog mechanism.

All plumbing job is done in the configuration file. The following code snippet shows this example:

   <add key="AzureStorageConnectionString" 
      <service name="Subscriber3">
                behaviorConfiguration="sharedSecretCredentials" />
      <endpoint name="TopicPublisher" 
                behaviorConfiguration="sharedSecretCredentials" />
      <endpoint name="QueuePublisher" 
                behaviorConfiguration="sharedSecretCredentials" />

        <behavior name="sharedSecretCredentials">
          <transportClientEndpointBehavior credentialType="SharedSecret">
              <sharedSecret issuerName="MY_ISSUER_NAME" issuerSecret="MY_ISSUER_SECRET" />
        <serviceMetadata httpGetEnabled="true"/>
        <serviceDebug includeExceptionDetailInFaults="false"/>
        <add name="transportClientEndpointBehavior" type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, 
Microsoft.ServiceBus, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add name="netMessagingTransport" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingTransportExtensionElement, 
Microsoft.ServiceBus, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
        <add name="netMessagingBinding" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingBindingCollectionElement, 
Microsoft.ServiceBus, Version=, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>

As you can see, there is an appSettings section for connection string to Azure Storage and the rest is a configuration for one Subscriber and two Publishers and of course, we have to put extensions for Service Bus such as transportClientEndpointBehavior, netMessagingTransportand netMessagingBinding.


That's all for the introduction. I hope you get the picture of the Service Bus position in the logical connectivity model between producers and consumers based on the WCF/WF Technology. I didn't describe a Service Bus management tools, creating Entities such as Queue, Topic, Subscription, etc. More about that, including their API programming can be found in the References. Also, I assume that you have a working knowledge of Windows Azure Platform and WCF/WF Technology.

OK, let's continue, there is lots of stuff to show before we getting into the usage and the test part.



The AzureMessagingActivityPack is a small package of the custom activities and class extensions for message mediation from/to Azure Service Bus Messaging. Its solution with full implementation is included in this article download. Basically, there are two groups, such as:

1. Endpoint and Class Extensions

This extensions have been created to simplify access and manipulation with BrokeredMessagePropertyBag. It can be used imperatively or declaratively in the xaml or config file.   

There are two classes extension such as MessagePropertiesExtensionand BrokeredMessagePropertyExtesion. The following example shows some of the usage.

var bmp = OperationContext.Current.IncomingMessageProperties.GetBrokeredMessageProperty();
long prop1 = bmp.RequiredItem<long>("prop1");
string prop2 = bmp.RequiredItem("prop2", "Missing {0} in the bag", "prop2");
XElement xbmp = bmp.ToXml();

var bmp1 = message.Properties.GetBrokeredMessageProperty("Missing BMP bag");
string prop3 = message.Properties.GetBrokeredMessageProperty().RequiredItem("prop3");



This is a client endpoint behavior extension to inject a BrokeredMessageProperty bag for outgoing message in the config file. Having this extension, we can "fire event interest" from the "legacy" Publisher to the Service Bus Topic channel.

public class MessagePropertyActionClientInspector : IClientMessageInspector
  public string Expression { get; set; }

  void IClientMessageInspector.AfterReceiveReply(ref Message reply, object correlationState)
    // nothing to do

  object IClientMessageInspector.BeforeSendRequest(ref Message request, IClientChannel channel)
    if (request.Properties.ContainsKey(BrokeredMessageProperty.Name))
      var bmp = request.Properties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;
      var sra = new SqlRuleAction(this.Expression);
      var bmp = new BrokeredMessageProperty();
      var sra = new SqlRuleAction(this.Expression);
      var bm = sra.Preprocess().Execute(bmp.Message);
      request.Properties.Add(BrokeredMessageProperty.Name, bmp);
    return null;

The core of the above inspector is the execution of the SqlExpression on the BrokeredMessage object.

The following code snippet shows its usage in the config file:

    <behavior name="sharedSecretClientCredentials">
      <transportClientEndpointBehavior credentialType="SharedSecret">
          <sharedSecret issuerName="MY_ISSUER_NAME" 
                           issuerSecret="MY_ISSUER_SECRET" />
      <!-- Set BrokeredMessageProperty Bag -->
      <messagePropertyAction enable="true" 
         expression="SET sys.Label='Router';SET sys.TimeToLive='00:01:00';SET id=newid()"/>

It can be used programmatically, as well:

  new RKiss.Activities.Azure.Messaging.MessagePropertyActionEndpointBehavior()
     Expression = "SET sys.Label='Router'; SET sys.TimeToLive='00:01:00'; SET id=newid()"



The BrokeredMessageFilter has been created for RoutingService to customize a message filtering on the BrokeredMessageProperty bag. It is a valuable extension for RoutingService Subscriber to forward a message to the proper outbound channel.

public class BrokeredMessageFilter : MessageFilter
  public string Expression { get; set; }

  public BrokeredMessageFilter(string expression)
    this.Expression = expression;

  public override bool Match(System.ServiceModel.Channels.Message message)
    if (message.Properties.ContainsKey(BrokeredMessageProperty.Name))
      var bmp = message.Properties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;                             
      var filter = new SqlFilter(this.Expression);
      bool bMatch = filter.Preprocess().Match(bmp.Message);
      return bMatch;
         return false;

  public override bool Match(System.ServiceModel.Channels.MessageBuffer buffer)
    throw new NotImplementedException();

The core of the above filter is executing a SqlFilter on the BrokeredMessage object. The following code snippet show usage this custom filter in the config file (routing section):

  <clear />
  <filter name="MatchForSubscriber1" 
    filterData="image=111 AND sys.Label='Hello Cloud'" 
    customType="RKiss.Activities.Azure.Messaging.BrokeredMessageFilter, RKiss.Activities.Azure.Messaging" />

Note, that the above extensions are very helpful for connecting "legacy" Pub/Sub producer and consumers to the Azure Service Bus via modification of their config files.

2. Custom Activities


AssignBMP<T> is a custom activity to create a BrokeredMessagePropertybag and assign it to the T type which can be accepted only for System.ServiceModel.Channels.Message or Microsoft.ServiceBus.Messaging.BrokeredMessageProperty types. Its design is based on the BrokeredMessageProperty class, where Service Bus properties (sys scope) and application (user) properties in the Parameters collection (user scope) are found:

Collection of the Parameters can be declared in the pop up dialog. The following picture shows an example of declaring different type of the user properties:


AssignBMP<T> is factorized for the required type T. The following code snippet shows these templates. It shows some examples of how we can predefine some common application properties in the collection of the parameters:

public class AssignBMPtoMessage : IActivityTemplateFactory
  public Activity Create(DependencyObject target)
    AssignBMP<Message> assign = new AssignBMP<Message>() 
      DisplayName = "AssignBMPtoMessage" 
    assign.Parameters.Add(new KeyValuePair<string,InArgument>("myKey", InArgument<string>.FromValue("12345")));

    return assign;

public class AssignToBMP : IActivityTemplateFactory
  public Activity Create(DependencyObject target)
    return new AssignBMP<BrokeredMessageProperty>() { DisplayName = "AssignToBMP" };



SendScope is a generic custom activity for Send Activity to allow declaratively way create a binding of the Send activity and dynamically inserting a message headers and properties:


This custom activity will allow adding a BrokeredMessageProperty bag for typed message contract, when the workflow orchestration is based on the clr types (DataContract). Note, that for untyped message, the BMP can be assigned directly to the message properties collection.



This custom activity is to subscribe a subscriber event interest to the Topic channel. The result of this custom activity is creating a subscription with one RuleDescription (name = $Default) based on the Filter and Action SqlExpression. 

Behind the Subscribe activity are API calls to the Service Bus, for checking existing subscription, then deleting (if Renew is required) and creating a new one. The current implementation of this custom activity is not full async process, only creating a subscription is done in the async manner, the others are sync process.

Note, that Azure SDK 1.5 doesn't support updating existing subscriptions. It would be nice to have this feature, instead of always deleting and recreating again and again. This process will impact all active subscribers relayed on this renewed subscription. To avoid this glitch, I recommend to use Empty Subscription and use API call for AddRuleto the subscription, in other words, keeping a subscription alive.



This is a custom activity to delete a subscription from the Topic channel in the async manner. It is very lightweight activity with requirement for Configuration, Namespace, Topic and Subscription names. Note, by processing this activity all active subscribers for this subscription are logically disconnected from the Topic channel.




This custom activity is useful for Susbcriber (Receiver) mediator to obtain operation context of the incoming message, which we need for getting a BrokeredMessageProperty bag that is sent by the Service Bus. This is a generic custom activity, originally created in the WF Security Pack CTP 1 and slightly modified in my package. The concept is very simple and straightforward such as creating an OperationContextin the workflow thread slot within its scope. To obtain a runtime OperationContext, implementation of the built-in message inspector interface such as System.ServiveModel.Activities.IReceiveMessageCallback and System.ServiveModel.Activities.ISendMessageCallback is used.


That's all for this package. I didn't create a full WF wrapper around the Service Bus API. The above extensions are focusing on the producer and consumer sides, which is publishing and consuming an event interest, creating a subscriber and its subscription. For managing Service Bus, we can use Windows Azure Platform portal and/or 3rd party explorers, like upcoming new version Service Bus Explorer.

OK, let's take a coffee break, because we are going to go through difficult parts such as Usage and Test. I am assuming, you have a working knowledge of the Windows Azure Platform.


Usage and Test

First of all, the following are prerequisites:

 Let's start with the Windows Azure Service Bus

Step 1. Create your Namespace on the Service Bus

Step 2. Create the following entities such as Queue and Topic in your Namespace scope

Step 3. Create Container 'box' in your Azure Storage Blob (this is an option for one test scenario - Test 3)

Step 4. Download this article and open it with VS2010SP1.

You should see the following solution:

Basically, the solution is divided into two parts such as AzureMessagingAcitivtyPackand Test. The first one is actually a package of the two assemblies to simplify consumption of the Service Bus. The usage of theses assemblies is shown in the Test package. As you can see, the Test folder contained different applications (scenarios) driven by WCF and WF Technologies using imperative and declarative ways to create producers and consumers.

Note, that the solution has been developed and tested on the Windows 7.

Step 5. Compile solution

In this step, you should have successfully built with the provided exe programs such as ConsoleApplications, Management, Publishers and PubSubRouter. All shortcuts are centralized into the ServiceBusTest folder, which can be added to the Desktop.

Step 6. Updating config files

Please, replace the following values in all config files located in the Test folder with your account for Azure Service Bus and Storage:


Step 7. Create Subscriptions

Launch the SubscriptionManagerprogram to create our test subscriptions:

This program has been created declaratively, using a workflow with a custom activity Subscribe. See its design in the following picture:

To verify the above subscriptions on the Service Bus, please launch the console program ManagingSubscriptionRules:

As you can see, we have three subscriptions, where the first one has a simple test Action expression. Note, that this test program is able to add one more rule into the subscription image12, which we will need to demonstrate later.

OK, now our test environment is ready for testing. But, one more comment. The Test Package also includes a simple message inspector for logging messages, including a BrokeredMessageProperty bag on the Console.


Test 1. Send message to the Queue.

This is a very simple test, the Sender will send a message to the Queue (Search) and the Receiver will retrieve the message from the queue. First (but not required) launch the Receiver console program:

and then the Sender console program:

You should see that the message has been received by Receiver:

Great, it's working. Now, you can launch one more Receiver and back to the Sender and press any key to send the message again. You will see that the message is balancing between the Receivers.

This test has been implemented declaratively within the config file. Please, visit these config files (Sender and Receiver) for more details. As you can see, migrating NetMsmqBinding(MSMQ) to NetMessagingBinding (Service Bus) can be straightforward and simple.

The following code snippet shows part of the Sender configuration file. There is messagePropertyAction element for setting BMP bag in the client endpoint behavior:


Test 2. Publish message to the Topic

In this test scenario, we are going to fire (publish) an event interest in advance of the Subscriber, therefore, please launch the Publish console program. The following screen snippet will show up. You can see the wcf message (yellow color) and the BMP bag (green color) on the console screen. Note, that the message has TTL setup for 30 minutes.


Now, launch the Subscriber console program. You should see the following result on your Subscriber:

That's great, we can see a log message with BMP bag as well as the deserialized  message in the service (white color).

Let's make more advance feature for this Pub/Sub scenario, where Subscriber subscribed subscription image12 with one $Default Rule such as image=111 or image=222, that's why we received only one message.

Now, let's add one more Rule to this subscription. We can do so by using a ManagingSubscriptionRules console program, which has this feature built-in (hard coded for test purposes). Please, go back to the ManagingSubscriptionRules program and press the 'a' key. You should see the same result like it is shown in the following screen snippet:

Note, that this Rule (name=abcd) has declared a RuleActionfor setting a user property Label.

Now, we can back to the Publisher console program and send a message to the Service Bus Topic channel by pressing a key (any key). This is a second message from the Publisher, therefore the counter value is 1. What is interesting in this test is that fact that the Subscriber received two messages from this subscription based on the successful expression of its RuleDescription. You can also see that the second message has the BMP bag different than first one. There is a result of the RuleAction such as SET Label = 'Hello Roman'.

That's cool, you can come back later and modify the test code for your RuleDescription, launching more Subscribers (may be on a different machine), etc. to see the capability of Pub/Sub on the Azure Service Bus.

This test has been created programmatically, the following code snippet shows implementation of the Publisher:

    // my Service Bus
    string issuerOwner = ConfigurationManager.AppSettings.Get("sbIssuerName");
    string issuerSecret = ConfigurationManager.AppSettings.Get("sbIssuerSecret");
    string namespaceAddress = ConfigurationManager.AppSettings.Get("sbNamespaceAddress");

    string text = string.Format("[{0}] Hello Service Bus - {1}", counter, DateTime.Now);

    EndpointAddress topicAddress = new EndpointAddress(namespaceAddress + "/" + topicName);

    var binding = new NetMessagingBinding();

    var securityBehavior = new TransportClientEndpointBehavior()
        TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerOwner, issuerSecret),

    var se = new ServiceEndpoint(ContractDescription.GetContract(typeof(INotify)), binding, topicAddress);
    se.Name = "TopicPublisher";
    se.Behaviors.Add(new RKiss.Logger.LoggerAttribute());

    factory = new ChannelFactory<INotify>(se);

    var channel = factory.CreateChannel();

    // programmatically setup bmp
    using (OperationContextScope scope = new OperationContextScope((IContextChannel)channel))
        var bmp = new BrokeredMessageProperty() { Label = "RKiss", TimeToLive = TimeSpan.FromMinutes(30) };
        bmp.Properties.Add("abcd", (long)12345);
        bmp.Properties.Add("image", (long)111);
        bmp.Properties.Add("id", Guid.NewGuid());
        bmp.Properties.Add("counter", (long)counter);
        OperationContext.Current.OutgoingMessageProperties.Add(BrokeredMessageProperty.Name, bmp);


    Console.WriteLine("Message #{0} has been sent to Topic='{1}'", counter++, topicName);
catch (CommunicationException ex)
    // ...
catch (Exception ex)
   // ...

Console.WriteLine("Press any key to send message");


Test 3. Event-driven Storage

This test is a scenario where you can see usage of the multiple technologies such as WCF, WF, Azure Blob Storage, Topic and Queue. The following picture shows this scenario:

Basically, we have Publisher, Subscriber and Cleaner components on the promise. On the Azure side we have a Blob Storage and Service Bus with a Queue and Topic channel. The action is very simple, the Publisher is putting a resource to the Blob Storage, firing an event to the Topic channel and sending a scheduled message to the queue to clean-up the resource in the Storage. This scenario is suitable to avoid a multicast delivering large messages. Instead of copying a large message for each subscription, the Service Bus will deliver a very small notification message to the subscriber(s) to pull a resource from the Storage. 

Note, that this test requires an option described in the prerequisites section such as azure storage account, creating a blob container and Azure Storage Explorer.

First of all, please launch the AzureStorageExplorer, connect your storage account and show the container 'box'. The following screen shows that for my account name (rkstorage):


next, launch the StorageReceiver console program:

Now, we can fire a Publisher, please launch the StoragePublisher program. Note, that Publisher will automatically perform an action and wait for next one, therefore please refresh the AzureStorageExplorer to see stored resource in the container 'box'.

Ok, the next step is to launch the StoragePublisher:

To verify, that our resource is stored in the Azure Blob Storage, please press the button Refresh on the following Explorer tool. You should see the following result:

Using this tool, we can also see actual resource in the browser. Note, that the watchdog time has been setup for 1 minute, after that, the Storage Cleaner receiver will receive a message from the queue to perform deleting a specific resource from the Blob Storage.

The following picture is a screen snippet about this action:

I know, the resource TTL time is to short (only 1 minute), however, you can go back to the StoragePublisher and fire an event again and focus on the specific action, etc. You can fire publisher multiple times and watch the Storage container 'box' for its contains.

I like this scenario, its implementation has been straightforward and readable. The following screen snippet shows a workflow of the StoragePublisher. There are full sequence of the Put and Notify activities, it is simple like 1-2-3.



Test 4. Router

This test is going to show a capability of the WCF4 Routing Service on the Service Bus. To better understand this test scenario, which requires launching more programs for producing and consuming messages, the following picture will give you a brief overview of this test scenario:


As you can see, this test scenario is more complex than previous one. Therefore, let's discuss it further. The goal of this test is to show the capability of the WCF RoutingService, which is the Subscriber and Publisher for Service Bus. The RoutingService can be a gateway from/to Service Bus. For this case, there is a WinForm program SimulatorPub/Sub to represent a WCF producer and subscriber or web service. It is a very simple program that sends or receives a Soap message.

On the other side, we have WCF/WF programs for Pub/Sub message and one program for receiving message from the queue. The following configuration snippet shows declaration of the all endpoints such as inbound and outbound endpoints for Router. Note, that Router subscribed its interest to Topic channel with subscription image1:

The logical connectivity between the Router and Service Bus is declared in the routing section. The following picture shows its filters. As you can see, this routing table supports three connectivity types (priority 9, 10 and 11). The first one has a custom message filter for BMP bag (image=111), the second one is based on the EndpointName, where any inbound message from the endpointRouteris forwarded to the outbound channel TopicPublisher1.The last one with, the highest priority 11, is based on the message Action. If this match is true, the message is forwarded to the Service Bus Queue.

Please, have a look at the full configuration file PubSubRouter.exe.config for its contents, specially at the endpoint behavior section.

I hope you understand this config file,  especial the routing table, which is necessary for our next step such as runtime use cases:

Please, close all opened programs and launch the following programs:

  1. PubSubRouterconsole program (this is a host process for Routing Service)
  2. SimulatorPubSubwinform program to simulate Pub/Sub messages
  3. Subscriberconsole program for receiving messages from the Service Bus Topic
  4. Receiverconsole program for receiving messages from the Service Bus Queue

At this moment, you should see on all console programs, a prompt message for listeners. Our SimulatorPubSub has already predefined a Pub message, so our test scenario is waiting for an event. We are going to make three use cases, such as the event is sent by simulator, event from the Topic is received by simulator and one more case when simulator will send a message to the Queue.

1. Simulator is firing an event_1 message

Please, press the button OneWay on the SimulatorPubSub. You should see the log messages on the PubSubRouter console program and on the Receiver, so, our message from the simulator has been sent via Router to the Service Bus Queue and received by the Receiver console program, see the following screen snippet:


2. Simulator is firing an event_2 message

In this case, simulator will send a different event message. Please, modify Action for this message, for example, replace Broadcasterby BroadcasterXYZword and press the button OneWay for sending this message. You should see on the Subscriber console program the following result:

and on the Simulator Sub message from the subscription image1:

That's great. What happens here? Well, the inbound message from the Pub Simulator has been routed to the Topic channel and all subscribers (which is also a Sub Simulator) with subscription image1received a copy message from the Service Bus Topic.

Ok, let's make one more case. Please, press button Clear to erase a Sub message on the Simulator.

3. WorkflowPublisher1 is firing an event message

In this case, we are going to publish a message to the Service Bus Topic. For this test, we need to launch WorkflowPublisher1 console program. Please, do that and watch the results on the console programs.

First of all, we can see that the Subscriber received two messages (different BMP bag but the same message payload). That's correct, this subscriber subscribed for image12subscription, which at this moment has two RuleDescriptions, that's way we received two copies of the message:

We can see on the other result on the Simulator, where a Sub message has been received. You can check the message payload for its element id.

That's all for this test. One more note, please have a look at the PubSubRouter console program. You will see the log messages for inbound and outbound endpoints including their BMP bag.

If everything is goes well, try to modify the routing table, publishers and/or subscriber in this scenario to create new use cases in order to see how the WCF and WF Technologies work with Azure Service Bus Topic/Queue.


Test 4. Subscribers hosted on the IIS/WAS

The Subscriber folder is included in the Test package. This folder contains an implementation of the three subscribers hosted in the IIS/WAS server. One subscriber is implemented declaratively using a workflow xaml.  The following code snippet subscriber is created imperatively by the code::

public class Subscriber1 : IGenericOneWayContract
  public void Message(System.ServiceModel.Channels.Message msg)
    Trace.WriteLine("*** Subscriber1 ***");
    if (msg.Properties.ContainsKey(BrokeredMessageProperty.Name))
        var bmp = msg.Properties[BrokeredMessageProperty.Name] as BrokeredMessageProperty;
        foreach (var prop in bmp.Properties)
            Trace.WriteLine(string.Format("  {0} = {1}", prop.Key, prop.Value));

    Trace.WriteLine(msg + "\r\n");

and the following screen snippet shows Subscriber3 created by WF. You can see the usage of the OperationContextScopeto obtain a message BMP bag:

The complete plug-in setup to the Service Bus is done in the configuration file. Please, visit this file to understand each subscriber hosted by IIS/WAS. Note, that this virtual application must have the Auto-Start feature enabled.

I will leave this test for you and I hope you will see the result of the subscribers on the trace output such as DebugView. You can use the Publisher console program to fire an event to the Topic channel.



Advanced usage

Windows Azure Service Bus Messaging offers advanced features such as receiving message in the PeekLockmode, when a message is removed from the Queue/Subscription after the client will send a request to complete the message, client batching processing, session-full messaging, etc. These advanced features are not described in this article. More details can be found in the Service Bus Brokered Messaging Performance - Best Practices Guide.

In this article, we used access to the Service Bus by .Net API clients (wrapped by wcf paradigm) implemented in the Azure SDK. The REST API can be used for .Not application with some limitations. Please, read more about this in Service Bus REST API Reference.



This article described usage of the Windows Azure Service Bus Messaging by WCF and WF Technologies. The Azure Service Bus Messaging is built in the multi-tenant environment and it represents a logical connectivity between its producers and consumers located on promises and/or Azure environments. The Service Bus is not a technology, it is a service solution for queuing and Pub/Sub messaging for event-driven architecture and intra-application message exchange in the transparent loosely decouple manner. Definitely, the Azure Service Bus plays a significant role in the business model for mapping a centralized logical connectivity to the decentralized physical one. I hope you enjoyed this article. 



[1] Service Bus

[2] Windows Azure AppFabric Service Bus Brokered Messaging

[3] Service Bus Brokered Messaging Performance - Best Practices Guide

[4] Service Bus Topics and Queues – Advanced

[5] The Windows Azure AppFabric Service Bus: Topics

[6] Exploring Azure AppFabric Service Bus V2 May CTP: Topics

[7] Best Practices for Leveraging Windows Azure Service Bus Brokered Messaging API

[8] How to integrate a BizTalk Server application with Service Bus Queues and Topics

[9] Overview of Creating a Hosted Service for Windows Azure

[10] Creating a Hosted Service for Windows Azure

[11] Exploring Topics and Queues by Building a Service Bus Explorer Tool–Part 1

[12]  Windows Azure AppFabric Samples

[13] Azure AppFabric Service Bus Brokered Messaging GA & Rude CTP Diffs

[14] Exploring Azure AppFabric Service Bus V2 May CTP: Queues

[15] SqlExpression

[16] Service Bus Samples on CodePlex

[17] Using Service Bus Topics and Subscriptions with WCF





This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Roman Kiss
Software Developer (Senior)
United States United States
No Biography provided

You may also be interested in...

Comments and Discussions

QuestionCan a Web service use Azure service bus? Pin
Member 116651176-May-15 3:13
memberMember 116651176-May-15 3:13 
GeneralMy vote of 4 Pin
hebsiboy29-Apr-13 2:23
memberhebsiboy29-Apr-13 2:23 
GeneralMy vote of 5 Pin
Member 145990212-Apr-13 23:07
memberMember 145990212-Apr-13 23:07 
GeneralMy vote of 5 Pin
Kanasz Robert28-Sep-12 5:34
mvpKanasz Robert28-Sep-12 5:34 
Questionvery good Pin
v-yunqua14-Mar-12 20:59
memberv-yunqua14-Mar-12 20:59 
GeneralMy vote of 5 Pin
lokeshsp5-Nov-11 6:00
memberlokeshsp5-Nov-11 6:00 
QuestionNice article Pin
GanesanSenthilvel3-Nov-11 17:36
memberGanesanSenthilvel3-Nov-11 17:36 
GeneralMy vote of 5 Pin
Nickos_me2-Nov-11 2:45
memberNickos_me2-Nov-11 2:45 
GeneralMy vote of 5 Pin
jim lahey1-Nov-11 23:19
memberjim lahey1-Nov-11 23:19 
GeneralMy vote of 5 Pin
sam.hill1-Nov-11 8:41
membersam.hill1-Nov-11 8:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150804.4 | Last Updated 1 Nov 2011
Article Copyright 2011 by Roman Kiss
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid