AppFabric Apps (June 2011 CTP) Accessing AppFabric Queue via REST


I recently watched an episode of AppFabric TV where they were discussing the REST API for Azure AppFabric.  I thought the ability to access the AppFabric Service Bus, and therefore other Azure AppFabric services like Queues, Topics and Subscriptions via REST was a pretty compelling scenario.  For example, if we take a look at the “Power Outage” scenario that I have been using to demonstrate some of the features of AppFabric Applications, it means that we can create a Windows Phone 7 (or Windows Phone 7.1/Mango Beta) application and dump messages into an AppFabric Queue securely via the AppFabric Service Bus.  Currently, the Windows Phone SDK does not allow for the managed, Service Bus bindings to be loaded on the phone so using the REST based API over HTTP is a viable option.

Below is a diagram that illustrates the solution that we are about to build.  We will have a Windows Phone 7.1 app that will push messages to an Azure AppFabric Queue.  (You will soon discover that I am not a Windows Phone developer.  If you were expecting to see some whiz bang new Mango features then this post is not for you.) 

The purpose of the mobile is to submit power outage information to an AppFabric Queue.  But before we can do this we need to retrieve a token from the Access Control Service and include this token in our AppFabric Queue message Header.  Once the message is in the Queue,  we will once again use a Code Service to retrieve messages that we will then insert into a SQL Azure table.

image

 

Building our Mobile Solution

One of the benefits of using AppFabric queues is the loose coupling between publishers and subscribers.  With this in mind, we can proceed with building a Windows Phone 7 application in its own solution.  For the purpose of this blog post I am going to use the latest mango beta sdk bits which are available here.

image

Since I have downloaded the latest 7.1 bits, I am going to target this phone version.

image

 

On our WP7 Canvas we are going to add a few controls:

  • TextBlock called lblAddress that has a Text property of Address
  • TextBox called txtAddress that has an empty Text Property
  • Button called btnSubmit that has a Content property of Submit
  • TextBlock called lblStatus that has an empty Text Property

image

 

Within the btnSubmit_Click event we are going to place our code that will communicate with the Access Control Service.

private void btnSubmit_Click(object sender, RoutedEventArgs e)
     {

         //Build ACS and Service Bus Addresses
         string acsAddress = https + serviceNameSpace + acsSuffix ;
         string relyingPartyAddress = http + serviceNameSpace + serviceBusSuffix;
         string serviceAddress = https + serviceNameSpace + serviceBusSuffix;

         //Formulate Query String
         string postData = "wrap_scope=" + Uri.EscapeDataString(relyingPartyAddress) +
             "&wrap_name=" + Uri.EscapeDataString(issuerName) +
             "&wrap_password=" + Uri.EscapeDataString(issuerKey);
        
     
         WebClient acsWebClient = new WebClient();
        
         //Since Web/Http calls are all async in WP7, we need to register and event handler
         acsWebClient.UploadStringCompleted += new UploadStringCompletedEventHandler(acsWebClient_UploadStringCompleted);

         //instantiate Uri object with our acs URL so that we can provide in remote method call
         Uri acsUri = new Uri(acsAddress);
        
         acsWebClient.UploadStringAsync(acsUri,"POST",postData); 

}

 

Since we are making an Asynchronous call to the ACS service, we need to implement  the   handling of the response from the ACS Service.

private void acsWebClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            lblStatus.Text = "Error communicating with ACS";
        }
        else
        {
            //store response since we will need to pull ACS token from it
            string response = e.Result;

            //update WP7 UI with status update
            lblStatus.Text = "Received positive response from ACS";
           
            //Sleep just for visual purposes
            System.Threading.Thread.Sleep(250);

            //parsing the ACS token from response
            string[] tokenVariables = response.Split(‘&’);
            string[] tokenVariable = tokenVariables[0].Split(‘=’);
            string authorizationToken = Uri.UnescapeDataString(tokenVariable[1]);

          
           //Creating our Web client that will use to populate the Queue
            WebClient queueClient = new WebClient();

            //add our authorization token to our header
            queueClient.Headers["Authorization"] = "WRAP access_token=\"" + authorizationToken +"\"";
            queueClient.Headers[HttpRequestHeader.ContentType] = "text/plain";

            //capture textbox data
            string messageBody = txtAddress.Text;
          
            //assemble our queue address
            //For example: "
https://MyNameSpace.servicebus.appfabriclabs.com/MyQueueName/Messages"
            string sendAddress = https + serviceNameSpace + serviceBusSuffix + queueName + messages;

            //Register event handler
            queueClient.UploadStringCompleted += new UploadStringCompletedEventHandler(queueClient_UploadStringCompleted);

            Uri queueUri = new Uri(sendAddress);
            //Call method to populate queue
            queueClient.UploadStringAsync(queueUri, "POST", messageBody);
        }

       

    }

So at this point we have made a successful request to ACS and received a response that included our token.  We then registered an event handler as we will call the AppFabric Service Bus Queue using an Asynchronous call.  Finally we made a call to our Service Bus Queue.

We now need to process the response coming back from the AppFabric Service Bus Queue.

private void queueClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
    //Update status to user.
    if (e.Error != null)
    {
        lblStatus.Text = "Error sending message to Queue";
    }
    else
    {
         lblStatus.Text = "Message successfully sent to Queue";
    }
}

 

That concludes the code that is required to submit a message securely to the AppFabric Service Bus Queue using the Access Control Service to authenticate our request.

Building our Azure AppFabric Application

The first artifact that we are going to build is the AppFabric Service Bus Queue called QueueMobile.

image_thumb2[1]

Much like we have done in previous posts we need to provide an IssuerKey, IssuerName and Uri.

image_thumb4

The next artifact that we need add is a SQL Azure Database.

image26_thumb

Adding this artifact is only the beginning.  We still need to create our local database in our SQL Express instance.  So what I have done is manually created a Database called PowerOutage and a Table called Outages.

image_thumb6

Within this table I have two very simple columns: ID and Address.

image_thumb10

So the next question is how do I connect to this database.  If you navigate to the AppFabric Applications Manager which is found within the AppFabric Labs portal, we will see that a SQL Azure DB has been provisioned for us.

image_thumb12

Part of this configuration includes our connection string for this Database.  We can access this connection string by clicking on the View button that is part of the Connection String panel.

image_thumb13

I have covered up some of the core credential details that are part of my connection string for security reasons.  What I have decided to do though to make things a little more consistent is created a SQL Server account that has these same credentials in my local SQL Express.  This way when I provision to the cloud I only need to change my Data Source.

image_thumb17

For the time being I am only interested my local development fabric so I need to update my connections string to use my local SQL Express version of the database.

 

image_thumb19

With our Queue and Database now created and configured, we need to focus on our Code Service.  The purpose of this Code Service is to retrieve messages from our AppFabric Queue and insert them into our SQL Azure table.  We will call this Code Service CodeMobileQueue and then will click the OK button to proceed.

image17_thumb

We now need to add references from our Code Service to both our AppFabric Queue and our SQL Azure Instance.  I always like to rename my references so that they have meaningful names.

image_thumb5

Inside our Code Service, It is now time to start focusing on the plumbing of our solutions We need to be able to retrieve messages from the AppFabric Queue and insert them into our SQL Azure table.

public void Run(CancellationToken cancelToken)
      {
        
           //Create reference to our Queue CLient
            QueueClient qClient = ServiceReferences.CreateQueueMobile();
          
          //Create reference to our SQL Azure Connection
            SqlConnection sConn =  ServiceReferences.CreateSqlQueueMobile();
            MessageReceiver mr = qClient.CreateReceiver();
            BrokeredMessage bm;
            
           Stream qStream;
           StreamReader sReader;
           string address;

            System.Diagnostics.Trace.TraceInformation("Entering Queue Retrieval " + System.DateTime.Now.ToString());

            while (!cancelToken.IsCancellationRequested)
            {
                //Open Connection to the database
                sConn.Open();
              
                while (mr.TryReceive(new TimeSpan(hours: 0, minutes: 30, seconds: 0), out bm))
                {

                    try
                    {
                        //Note: we are using a Stream here instead of a String like in other examples
                        //the reason for this is that did not put the message on the wire using a
                        //BrokeredMessage(Binary Format) like in other examples.  We just put on raw text.
                        //The way to get around this is to use a Stream and then a StreamReader to pull the text out as a String
                        qStream = bm.GetBody<Stream>();
                        sReader = new StreamReader(qStream);
                        address = sReader.ReadToEnd();

                        //remove message from the Queue
                        bm.Complete();

                        System.Diagnostics.Trace.TraceInformation(string.Format("Message received: ID= {0}, Body= {1}", bm.MessageId, address));

                       //Insert Message from Queue and add it to a Database
                        SqlCommand cmd = sConn.CreateCommand();
                        cmd.Parameters.Add(new SqlParameter("@ID", SqlDbType.NVarChar));
                        cmd.Parameters["@ID"].Value = bm.MessageId;
                        cmd.Parameters.Add(new SqlParameter("@Address", SqlDbType.NVarChar));
                        cmd.Parameters["@Address"].Value = address;
                        cmd.CommandText = "Insert into Outages(ID,Address) Values (@ID,@Address)";
                        cmd.CommandType = CommandType.Text;
                        cmd.ExecuteNonQuery();
                        System.Diagnostics.Trace.TraceInformation("Record inserted into Database");
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Trace.TraceError("error occurred " + ex.ToString()); 
                    }
                }

                // Add your code here
                Thread.Sleep(5 * 1000);
            }

            mr.Close();
            qClient.Close();
            sConn.Dispose();

         
      }

Testing Application

We are done with all the coding and configuration for our solution.  Once again I am going to run this application in the local Dev Fabric so I am going to go ahead and type CRTL + F5.  Once my Windows Azure Emulator has been started and our application has been deployed we can start our Windows Phone Project.

For the purpose of this blog post we are going to run our Windows Mobile solution in the provided emulator.  However, I have verified the application can be side-loaded on a WP7 device and the application does work properly.

We are now going to populate our Address text box with a value.  In this case I am going to provide 1 Microsoft Way  and click the Submit button.

image_thumb[1]

Once we click the Submit button we can expect our first status message update indicating that we have received a positive response from ACS.

image_thumb[5]

The next update we will have displayed is one that indicates our message has been successfully sent to our AppFabric Queue.

image_thumb[3]

As outlined previously, our WP7 app will publish message to our AppFabric Queue, from there we will have our Code Service de-queue the message and then insert our record into a SQL Azure table.  So if we check our Outages table we will discover that a record has been added to our Database.

 

image_thumb[7]

 

Conclusion

Overall I am pretty please with how this demo turned out.  I really like the ability to have a loosely coupled interface that a Mobile client can utilize.  What is also nice about using a RESTful interface is that we have a lot of flexibility when porting a solution like this over to other platforms.

Another aspect of this solution that I like is having a durable Queue in the cloud.  In this solution we had a code service de-queuing this message in the cloud.  However, I could also have some code written that is living on-premise that could retrieve these messages from the cloud and then send them to an LOB system like SAP.  Should we have a planned, or unplanned system outage on-premise, I know that all mobile clients can still talk to the Queue in the cloud.

Advertisements

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s