CHAPTER 3 ■ WORKING WITH CLOUD QUEUE AND BLOB STORAGE 73 bool containerAndQueueCreated = false; while (!containerAndQueueCreated) { try { queue.CreateQueue(); containerAndQueueCreated = true; } catch (WebException e) { if (e.Status == WebExceptionStatus.ConnectFailure) { RoleManager.WriteToLog( "Error", string.Format("Connect failure! The most likely reason is that the local Development Storage tool is not running or your storage account configuration is incorrect. " + "Message: '{0}'", e.Message) ); System.Threading.Thread.Sleep(5000); } else { throw; } } } while (true) { try { Message msg = queue.GetMessage(); if (msg != null) { string path = msg.ContentAsString(); RoleManager.WriteToLog("Information", string.Format("Done with '{0}'", path)); } else { Thread.Sleep(1000); } } catch (StorageException e) { RoleManager.WriteToLog( "Error", string.Format("Exception when processing queue item. Message: '{0}'", e.Message) CHAPTER 3 ■ WORKING WITH CLOUD QUEUE AND BLOB STORAGE 74 ); } } } public override RoleStatus GetHealthStatus() { // This is a sample worker implementation. Replace with your logic. return RoleStatus.Healthy; } } } Create the Queue Programatically Listing 3-3 is an example of creating a queue programatically inside a C# class instead of reading the information from a configuration file. This code snippet can be used to replace the highlighted part in Listing 3-2. Listing 3-3. Create the Queue Programatically string accountName = "devstoreaccount1"; string accountKey = "<ACCOUNT KEY>"; string address = "http://127.0.0.1:10001"; StorageAccountInfo accountInfo = new StorageAccountInfo(new Uri(address), null, accountName, accountKey); QueueStorage queueStorage = QueueStorage.Create(accountInfo); MessageQueue messageQueue = queueStorage.GetQueue(XML PAYLOAD QUEUE NAME); Before a client can access the cloud queue one of the two initialization steps shown in the previous listing is required. Put a Message into the Queue There are three data types you can use as a raw queue message: stream, byte array, and string. In this exercise we are going to use the class Address defined in Chapter 1 and Chapter 2 as a data entity class. Since XML is the most popular data exchange format, we are going to transform the data of an instance of Address into an XML string by using the .NET XmlSerialization class and put it into the queue as a message. Listing 3-4 shows the code to transform the data entity Address into an XML string and put it into the queue as a queue message. CHAPTER 3 ■ WORKING WITH CLOUD QUEUE AND BLOB STORAGE 75 Unlike the behavior of a regular Windows queue object, when a message is put into the cloud queue it can be read (de-queued) multiple times by applications. The message will not be removed from the queue until another service calls to delete the queue explicitly. The message body is encoded and stored in a data field of the Message table after the message has been put into the queue. Figure 3-5 shows the data query results from the local database when the message is submitted to the queue in the local development environment. The data has been encoded as you can see. Listing 3-4. Convert Address Data Entity Object into XML String and Put into Queue protected void btnAddAddress Click(object sender, EventArgs e) { if (Page.IsValid) { GetXmlPayloadQueue().PutMessage(new Message( ComposeXmlString())); } } private string ComposeXmlString() { Address address = new Address(txtAddress1.Text.Trim(), txtAddress2.Text.Trim(), txtCity.Text.Trim(), (State)combState.SelectedIndex, txtZip.Text.Trim(), txtCounty.Text.Trim(), txtCountry.Text.Trim(), string.Empty); XmlSerializer serializer = new XmlSerializer(address.GetType()); StringBuilder sb = new StringBuilder(); StringWriter writer = new StringWriter(sb); serializer.Serialize(writer, address); return writer.GetStringBuilder().ToString(); } private BlobContainer GetXmlPayloadContainer() { Initialization(); return blobStorage.GetBlobContainer(WorkerRole.XML CONTAINER NAME); } private MessageQueue GetXmlPayloadQueue() { Initialization(); return queueStorage.GetQueue(WorkerRole.XML PAYLOAD QUEUE NAME); } CHAPTER 3 ■ WORKING WITH CLOUD QUEUE AND BLOB STORAGE 76 protected void btnDelete Click(object sender, EventArgs e) { Message message = GetXmlPayloadQueue().GetMessage(UPDATE TIMEOUT SEC); if (message != null) { GetXmlPayloadQueue().DeleteMessage(message); } } Figure 3-5. Queue message persisted in data field of Message table and encoded Poll and Delete a Message from the Queue The MessageQueue class defined in the StorageClient assembly also provides polling infrastructure under the covers and delivers the message via venting. The default poll interval setting in the MessageQueue class is 30 seconds. This polling interval value can be set during initialization of a queue instance. Listing 3-5 is the initialization handler implemented in the code behind Default.aspx.cs. To receive the queue polling events, a local event-handler function needs to be defined. The event handler function is called private void OnMessageReceive(object sender, EventArgs args), which has the typical event-handler signature with two parameters. The first parameter is the basic object type, and the second parameter is the EventArgs type. The application can have any logic it needs in the event-polling handler. In this example, we simply print out the content of the message polled from the queue. As the highlighted part shows in Listing 3-5, the event handler is hooked up right after the queue is created. This function also uses the synchronization object syncObj to make it thread-safe in a multi-thread environment. CHAPTER 3 ■ WORKING WITH CLOUD QUEUE AND BLOB STORAGE 77 ■ Note Never call queue.StartReceiving() if there is no event handler such as queue.MessageReceived += new MessageReceivedEventHandler( OnMessageReceive) implemented in the class. Otherwise it causes a NullObject reference exception to be thrown at runtime. Listing 3-5. Polling the Queue and Handling Received Events private void Initialization() { if ( initialized) { return; } lock ( syncObj) { try { queueStorage = QueueStorage.Create(StorageAccountInfo .GetDefaultQueueStorageAccountFromConfiguration()); MessageQueue queue = queueStorage.GetQueue(WorkerRole.XML PAYLOAD QUEUE NAME); queue.MessageReceived += new MessageReceivedEventHandler(_OnMessageReceive); queue.PollInterval = 1000; // in milliseconds queue.StartReceiving(); // start polling } catch (WebException ex) { throw new WebException( string.Format( " {0}: Initialization, Azure failed to instatiate storage using current account information. exception caught : {1}", this.ToString(), ex.Message ) ); } initialized = true; } } private void OnMessageReceive(object sender, EventArgs args) { Message message = (args as MessageReceivedEventArgs).Message; . CHAPTER 3 ■ WORKING WITH CLOUD QUEUE AND BLOB STORAGE 75 Unlike the behavior of a regular Windows queue object, when a message is put into the cloud queue it can be read (de-queued) multiple