(…Continued from Part 1, if you have not read it please do so to understand the context of this post)
Solution
We want customers to be able to submit power outages to our fictitious power company located in the Redmond, Washington area. What is different this time around(from our Queue scenario) is that due to the growth in the Kirkland, Washington area we have subcontracted power line maintenance to another company. So we want our Redmond system to receive messages for the Redmond area and this other company to receive messages for Kirkland. The Redmond company should not see the Kirkland messages and vice versa.
Configuring Core Artifacts
The user interface for this application will once again be an ASP.Net Web Application. We will add this Web Application by clicking on the Add New Service label which is found on the AppFabric Design View Canvas.
Next, we will want to provide an appropriate name for this Web App and click on the OK button.
We now need to create a Service Bus Topic and can do this by once again clicking on the Add New Service label which is found on the AppFabric Design View Canvas.
Much like we have had to do with other Service Bus artifacts, we need to provide our Service Bus IssuerKey, IssuerName and Uri. For my URI, I have provided the following value:
sb://<your_namespace>.servicebus.appfabriclabs.com/SimpleServiceBusTopic
Note: Notice the RequiresProvisioning property which is set to True. When we deploy our AppFabric application the provisioning of our Topic will be taken care of without any additional work from our side. When we shutdown the Azure Compute Emulator, this Topic will be removed.
In many of the May AppFabric CTP examples out there people handle provisioning tasks by using the ServiceBusNamespaceClient class. No where in this code will we be directly using this class. I would imagine that under the hood, the provisioning code is using this class.
Next, our Web application we need to add a reference to this newly created Topic.
I like to rename my references to provide a more descriptive title than the default Import1 value.
With our topic now setup we want to add two subscriptions. The first subscription will be for our Redmond messages and the second subscription will be for our Kirkland subscription.
Kirkland
For each of these Subscriptions we need to once again provide IssuerKey, IssuerName and Uri properties. The Uri property for subscriptions provides an interesting twist. The actual word “subscriptions” must be included between the name of your Topic and Subscription. The convention for these Uri are:
sb://your_namespace.servicebus.appfabriclabs.com/TopicName/subscriptions/SubscriptionName
Much like in the Queue Blog Post we are going to use a Code Service to retrieve messages from our Topic via a Subscription. We need once again click on the Add New Service label and select Code.
This Code Service will represent the Redmond Client and therefore we need to add a reference to the SimpleServiceBusSubscriptionRedmond Subscription.
The underlying core of our application should be set and we should be able to build our application. If we look at the AppFabric Design View Canvas we should see the following:
Our Diagram View should look like this:
Update Web Application
At this point we have simply configured all of the artifacts that are required in our solution but we have not written any code so our application will not be very functional. In the Source view of the Default.aspx page we want to add a few controls:
- Text Box for our Address
- Text Box for our City
- Button used to submit our form
In the code behind for Default.aspx we will want to add an event handler for the Button clicked event.
protected void btnSubmit_Click(object sender, EventArgs e)
{
TopicClient tc = ServiceReferences.CreateSimpleServiceBusTopic();
MessageSender ms = tc.CreateSender();
BrokeredMessage bm = BrokeredMessage.CreateMessage(txtAddress.Text);
bm.Properties[“OutageCity”] = txtCity.Text;
ms.Send(bm);
txtAddress.Text = “”;
txtCity.Text = “”;
}
Some lines of significance include:
TopicClient tc = ServiceReferences.CreateSimpleServiceBusTopic(); where we are creating an instance of our TopicClient.
The BrokeredMessage instantiation line includes our message body which is our address that is coming from our Address text box.
BrokeredMessage bm = BrokeredMessage.CreateMessage(txtAddress.Text);
You may also notice where we assign our City value to a property called OutageCity. This property is kinda like a BizTalk Context property. We are going to be able to route our message based upon this value. We will later use this property when creating a Subscription Filter.
bm.Properties[“OutageCity”] = txtCity.Text;
Note: this code looks a little different than the May AppFabic CTP code that you have seen. In the May CTP we had to worry about our Service Bus configuration for our namespace, Issuer owner and key. We also had to create an instance of a MessagingFactory object so that we could create a Topic Client. I like the AppFabric Application approach better. It is a little cleaner and all of our configuration info is handled in our Application model.
Update Code Service
We now need to update our Run method that exists within our Code Service. As discussed in the Queue blog post, this method will continue to run until a cancellation request is received. The purpose of this method is to retrieve messages from our Topic via our Redmond Subscription.
For the purpose of this demonstration we are simply going to log messages that have been retrieved in our Trace viewer.
public void Run(CancellationToken cancelToken)
{
System.Diagnostics.Trace.TraceInformation(“Entering Code Service Loop”);
while (!cancelToken.IsCancellationRequested)
{
SubscriptionClient subClient = ServiceReferences.CreateSimpleServiceBusSubscription();
subClient.MessagingFactory.CreateSubscriptionClient(“SimpleServiceBusTopic”, “SimpleServiceBusSubscriptionRedmond”);
MessageReceiver mr = subClient.CreateReceiver();
BrokeredMessage bm;
while (mr.TryReceive(new TimeSpan(hours: 0, minutes: 0, seconds: 5), out bm))
{
System.Diagnostics.Trace.TraceInformation(string.Format(“Message received: ID= {0}, Body= {1}”, bm.MessageId, bm.GetBody<string>()));
bm.Complete();
}
// Add your code here
Thread.Sleep(5 * 1000);
}
}
Some lines of significance include:
Our line where we create a subscription client that will include the name of our Topic and our Subscription.
subClient.MessagingFactory.CreateSubscriptionClient(“SimpleServiceBusTopic”, “SimpleServiceBusSubscriptionRedmond”);
The next line is our while loop that will attempt to retrieve messages from this subscription. If a message is retrieved it will be stored in a BrokeredMessage.
while (mr.TryReceive(new TimeSpan(hours: 0, minutes: 5, seconds: 0), out bm))
Creating a Kirkland client
Our Kirkland client is going to follow a different path than our Redmond client. At this point everything that we have built exists in the Azure Cloud. For our Kirkland client, it is going to reside on-premise. Since our Topics and Subscriptions are provisioned in the cloud we can access them from within the cloud and on-premise.
For this example we will follow the path that many of the May CTP examples took. It is a console application that is in a separate solution from this AppFabric Application. In this application I have added references manually to the ServiceBus CTP assemblies.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using Microsoft.ServiceBus.Description;
namespace SimpleTopicOnPrem
{
class Program
{
static void Main(string[] args)
{
Uri sbURI = ServiceBusEnvironment.CreateServiceUri(“sb”, “<your_namespace>”, string.Empty);
string name = “owner”;
string key = “<your_key>”;
MessagingFactory factory = MessagingFactory.Create(sbURI, TransportClientCredentialBase.CreateSharedSecretCredential(name, key));
SubscriptionClient subClient = factory.CreateSubscriptionClient(“SimpleServiceBusTopic”, “SimpleServiceBusSubscriptionKirkland”);
//Next we create the MessageReceiver and receive a message.
MessageReceiver mr = subClient.CreateReceiver();
BrokeredMessage bm;
while (mr.TryReceive(new TimeSpan(hours: 0, minutes: 5, seconds: 0), out bm))
{
Console.WriteLine(string.Format(“Message received: ID= {0}, Body= {1}”, bm.MessageId, bm.GetBody<string>()));
bm.Complete();
}
Console.WriteLine(“Done Reading From Queue”);
Console.Read();
}
}
}
This code looks pretty similar to our Code Service with the exception of how we create a SubscriptionClient and that we need to deal with our credentials and URI in the application.
Testing the application
For the purpose of this blog post we are going to keep our AppFabric application in our Development Fabric. We can provision and deploy our application by typing CRTL + F5. We should see our web application launch.
Next we will want to start an instance of our Kirkland On Premise client by typing F5. This means that both of our applications are up and running and ready to receive messages.
Since we have not added any filters on our Subscriptions both applications should receive a copy of any message that we submit.
The first message that we will send will have an Address of Space Needle and a City of Seattle.
In our Trace logs and in our Console application we will discover that our message has been received by both clients.
At this point we have proved that our initial deployment has been successful and that we can broadcast this message to multiple clients. But, this is not the end state that we desire. Remember we want the Redmond client to only receive the Redmond messages and the Kirkland client to only receive the Kirkland messages. In order to accomplish this behavior we need to add Subscription rules.
Unless I have missed something(and please let me know if I have), there is no way to specify our filter when we create our Subscription through the AppFabric Design Canvas. The only way that I have seen how to do this is through code by using the ServiceBusNamespaceClient class. So I could have written this code but opted for a different option. The AppFabric Cat team recently released a tool called the Service Bus Explorer. Within this tool, you can provide your credentials and then interrogate your Queues, Topics and Subscriptions. You can read all about this tool and some more detailed information on their blog post.
Once I have connected to my namespace using the Service Bus Explorer, I want to navigate to my Redmond subscription and then delete the existing rule. Basically this rule is saying that any messages should be retrieved using this subscription.
I then want to right mouse click on the Redmond Subscription and Add Rule. I now need to provide a name for this rule (it can be anything) and a SQL Filter Expression. In this case I am providing OutageCity=’Redmond’.
With my Subscription rule established for my Redmond Subscription lets submit another message. This time we will provide an Address of 1 Microsoft Way and a City of Redmond.
So notice that both clients received this message. The reason for this is that this message did match the Subscription rule (filter) for the Redmond Client. Since we have not configured a Subscription rule (filter) for our Kirkland client it is still configured to receive all messages.
To prove that the Redmond Subscription is working, lets send in a message that will not match the Redmond rule. This time only the Kirkland application should receive it if we make the city equal to Bellevue.
We will discover that the Subscription rule is working. Our Redmond client did not receive this Bellevue message but our Kirkland client did since its Subscription rule is wide open.
So let’s create a Subscription rule for our Kirkland client. We will head back to the Service Bus Explorer tool to do this.
Once again we will delete the Default Rule, this time for the Kirkland Subscription. We will add a new Rule by right mouse clicking on the Kirkland Subscription and selecting Add Rule. We will provide this rule with a Name of Kirkland and a SQL Filter Expression of OutageCity=’Kirkland’.
With our Subscription rule now in place, lets send in a message that only our Kirkland client will receive.
Sure enough, our Redmond client did not receive a copy of this message since its Subscription rule didn’t match. Our Kirkland client did receive this message since it did match our Subscription rule
Closing Notes:
- You will lose any of these Subscription rules between deployments. When you shutdown the Dev Fabric emulator, your Topic and Subscriptions will be removed. When you deploy your application to the Local Dev fabric your Topic and Subscriptions will be deployed but your rules/filters will not return unless you configure them again.
- Topics will push messages to Subscriptions no matter the Rule that you have in place. But, clients will only retrieve messages that match the Subscription rule(s).
- You can have multiple Subscription rules per Subscription.
- It would be nice if we can provide our Subscription rules in our AppFabric Design view canvas. This way they could be deployed with our Topic and Subscription(s).
- Publishers instantiate TopicClient instances, Consumers instantiate Subscription Client instances.
- Overall the technology is pretty cool. Having true pub/sub in the cloud should open up many opportunities for organizations.