This tutorial demonstrates using a worker role and Windows Azure queue service.
You have probably noticed that the images are displayed in the original size, which takes a lot of space. In tutorial 4, you will expand the application with a new worker role in the background generating thumbnails based on the images. When the messages are listed, only the thumbnails are used.
Last reviewed: 11/4/2011
Note: Completing tutorial 1 and tutorial 3 are not a pre-requisites for this tutorial. However, it helps with understanding the scenario.
Note: The tutorial code has been tested on Windows Azure SDK (October 2012).
In this tutorial, you will learn how to:
Note the following requirements before you begin this lesson:
The following diagram illustrates the development components and the runtime components involved in this tutorial:
The Queue service architecture consists of a three-level hierarchy: accounts, queues, and messages. A Windows Azure storage account encompasses the Blob, Queue, and Table services. A queue is a logical destination for sending messages. There can be any number of queues in an account in the Queue service. A queue stores messages and makes them available to applications. Messages are stored in queues. There is no limit to the number of messages that can be stored in a queue, but the size of each individual message cannot exceed 8KB. To accommodate large object messages, you can put the large object in a blob and then send the URI of that object as a message to a queue. For more information, see Understanding Data Storage Offerings on the Windows Azure Platform, and Windows Azure Queue – Programming Queue Storage at http://go.microsoft.com/fwlink/?LinkId=153402.
In tutorial 1, you created the data model in the MessageBoard_Data project. In this lesson, you will modify the schema so that it includes an additional data member for the thumbnail URL. You will also add a member function for updating the thumbnail URLs. This function will be called from the worker role after the worker role generates the thumbnails.
In this lesson, you will go through the following procedures:
To open the Golfer Message Board application
In tutorial 1, you defined a fixed schema for the table to storage messages. You must modify the schema to include a new data member for storing the URL to the image in the Blob service.
To modify the table schema
public string ThumbnailURL {get; set;}
The file looks like the following after modification:
To modify the implementation of the object
using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D;
private const string messageQueueName = "golfermessageboardqueue"; //queue name must be in lower case private CloudQueueClient queueClient; private CloudQueue queue;
//create queue queueClient = storageAccount.CreateCloudQueueClient(); queue = queueClient.GetQueueReference(messageQueueName); queue.CreateIfNotExist();
//add message to the queue public void EnQueue(string uri, MessageBoardEntry entry) { // queue a message to process the image CloudQueueMessage message = new CloudQueueMessage(String.Format("{0},{1},{2}", uri, entry.PartitionKey, entry.RowKey)); queue.AddMessage(message); } public void ProcessQueueMessage() { // retrieve a new message from the queue CloudQueueMessage msg = queue.GetMessage(); if (msg != null) { // parse message retrieved from queue var messageParts = msg.AsString.Split(new char[] { ',' }); var imageBlobUri = messageParts[0]; var partitionKey = messageParts[1]; var rowkey = messageParts[2]; string thumbnailBlobUri = System.Text.RegularExpressions.Regex.Replace(imageBlobUri, "([^\\.]+)(\\.[^\\.]+)?$", "$1-thumb$2"); CloudBlob inputBlob = blobContainer.GetBlobReference(imageBlobUri); CloudBlob outputBlob = blobContainer.GetBlobReference(thumbnailBlobUri); using (BlobStream input = inputBlob.OpenRead()) using (BlobStream output = outputBlob.OpenWrite()) { CreateThumbnail(input, output); // commit the blob and set its properties output.Commit(); outputBlob.Properties.ContentType = "image/jpeg"; outputBlob.SetProperties(); // update the entry in the table to point to the thumbnail UpdateThumbnailURL(partitionKey, rowkey, thumbnailBlobUri); queue.DeleteMessage(msg); } } } //create thumbnail for an image private void CreateThumbnail(Stream input, Stream output) { int width; int height; var originalImage = new Bitmap(input); if (originalImage.Width > originalImage.Height) { width = 128; height = 128 * originalImage.Height / originalImage.Width; } else { height = 128; width = 128 * originalImage.Width / originalImage.Height; } var thumbnailImage = new Bitmap(width, height); using (Graphics graphics = Graphics.FromImage(thumbnailImage)) { graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.DrawImage(originalImage, 0, 0, width, height); } thumbnailImage.Save(output, ImageFormat.Jpeg); } //update the thumbnail URL property for an entry. public void UpdateThumbnailURL(string partitionKey, string rowKey, string thumbUrl) { TableServiceContext tableServiceContext = tableClient.GetDataServiceContext(); var results = from g in tableServiceContext.CreateQuery<MessageBoardEntry>(messageTableName) where g.PartitionKey == partitionKey && g.RowKey == rowKey select g; var entry = results.FirstOrDefault<MessageBoardEntry>(); entry.ThumbnailURL = thumbUrl; tableServiceContext.UpdateObject(entry); tableServiceContext.SaveChanges(); }
To rebuild the project
In Solution Explorer, right-click MessageBoard_Data, and then click Rebuild. Make sure the rebuild is successful.
In this step, you modified the data model.
You will modify the Web role.
Return to Top
In this lesson, you modify the markup so that the Web page displays the thumbnails instead of the original images. Each thumbnail is a link to a page displaying the original images. You also modify the code behind file for creating a queue and adding messages to the queue.
In this lesson, you will go through the following procedure:
To modify the markup
<div class="signatureImage"> <a href="<%# Eval("ImageUrl") %>" target="_blank"> <img src="<%# Eval("ThumbnailUrl") %>" alt="<%# Eval("GolferName") %>" /> </a></div>
The <div> tag looks like the following after the modification:
The following procedure demonstrates creating a queue and adding a message. A message may be up to 8KB in size and must be in a format that can be included in an XML request with UTF-8 encoding.
To modify the code-behind
MessageBoardEntry entry = new MessageBoardEntry() { GolferName = txtName.Text, GolferMessage = txtMessage.Text, ImageURL=blobURI, ThumbnailURL = blobURI};
ds.EnQueue(blobURI, entry);
In this step, you modified the Web role to communicate with the worker role for generating thumbnails in the background.
You will add a new worker role to the solution for background processing.
A worker role runs in the background to provide services or execute time-related tasks like a service process. In this lesson, you create a worker role to read work items posted to a queue by the Web role front-end. To process the work item, the worker role extracts information about a message board entry from the message and then retrieves the corresponding entity from the Table service. It then fetches the associated image from the Blob service and creates the thumbnail, which is also stored as a blob. Finally, to complete the processing, it updates the URL of the generated thumbnail blob in the message board entry.
To add a new worker role project
To modify the WorkerRole class
using MessageBoard_Data;
private MessageBoardDataSource ds;
ds = new MessageBoardDataSource();
public override void Run() { while (true) { ds.ProcessQueueMessage(); } }
To build the project
In Solution Explorer, right-click MessageBoard_WorkerRole, and then click Build. Make sure the rebuild is successful.
To add the storage account settings
Note: The Windows Azure storage emulator provides local instances of the Blob, Queue, and Table services that are available in the Windows Azure. For more information, see Overview of the Windows Azure Storage Emulator at http://msdn.microsoft.com/en-us/library/gg432983.aspx.
In this step, you added a new worker role to the solution for generating thumbnail images from given images in the background.
You will test and deploy the application.
In this lesson, you test the application in the development fabric environment, package the application, and then deploy the application to Windows Azure.
Note: If you don’t have a Windows Azure Platform subscription, see the Provisioning Windows Azure section of Windows Azure and SQL Azure Tutorials.
To test the application
After the application is tested successfully in the compute emulator environment, the next step is to create the service package and then deploy the application to Windows Azure. To generate the service package
You will get a few warning messages about 'DataConnectionString" set up to use the local storage emulator. You can ignore these warning for now.
For deploying the golfer message board application, you must have a storage account for accessing the Windows Azure storage services, and a cloud service, which is a container for service deployments in Windows Azure. For better performance, you might want to create an affinity group to group the service and the storage accounts within a subscription according to geo-location.
To sign in to Windows Azure
Note: If you haven’t had a Windows Azure Platform subscription, see the Provisioning Windows Azure section of this tutorial.
The next step is to create a storage account for using Windows Azure table service and blob service. If you have created a storage account in [[Windows Azure and SQL Database Tutorials - Tutorial 1: Using Windows Azure Web Role and Windows Azure Table Service (en-US)|tutorial 1]] or [[Windows Azure and SQL Database Tutorials - Tutorial 3: Using Windows Azure Blob Service (en-US)|tutorial 2]], you can skip this step.
To create a storage account for the golfer message board application to store its data
If you have published other tutorial projects before, you can either update the existing cloud service, or create a new cloud service. If you choose to create a new cloud service, you must give a different cloud service URL.
To create a cloud service
Note: The URL prefix must be unique.
When you create and test the application locally, the application is configured to use the development storage. Now you have created a storage account, you can configure the application to use the stroage account before deploying the application to Windows Azure. The configuration information is in the ServiceConfiguration.Cloud.cscfg file. This file was created when you generated the service package.
To configure the ServiceConfiguration.Cloud.cscfg file
To deploy the application to the staging environment
To test the application in the staging environment
After the application is working correctly in the staging environment, you are ready to promote it to the production environment.
To promote the application to production
Note: Some DNS services take longer to replicate the records. If you get a page not found error, you might need to try browsing to the URL again in a few minutes.
In this step, you tested and deployed the golfer message board to Windows Azure.
Congratulations! You have completed the first four Windows Azure and SQL Database tutorials. We will continue adding new tutorials.
Richard Mueller edited Revision 39. Comment: Replace RGB values with color names in HTML to restore colors
Richard Mueller edited Revision 38. Comment: Removed (en-US) from title, added tags
Carsten Siemens edited Revision 37. Comment: typo fixed
Cloud J edited Revision 32. Comment: Corrected filename in step 3 of 'To modify the table schema' from Default.aspx -> MessageBoardEntry.cs
Suirtimed edited Revision 31. Comment: corrected sentence syntax
Suirtimed edited Revision 30. Comment: Fixed typo
Ed Price - MSFT edited Revision 27. Comment: The "See Also" text was blue on blue. Made it white on blue.
Ed Price - MSFT edited Revision 25. Comment: TOC
Jonathan Gao edited Revision 24. Comment: update the architecture diagram
Jonathan Gao edited Revision 20. Comment: updating the architecture diagram