Exercise 1: Building Your First Windows Azure Application

In this exercise, you create a guest book application and execute it in the local development fabric. For this purpose, you will use the Windows Azure Tools for Microsoft Visual Studio to create the project using the Cloud Service project template. These tools extend Visual Studio to enable the creation, building and running of Windows Azure services. You will continue to work with this project throughout the remainder of the lab.

Note:
To reduce typing, you can right-click where you want to insert source code, select Insert Snippet, select My Code Snippets and then select the entry matching the current exercise step.

Task 1 – Creating the Visual Studio Project

In this task, you create a new Cloud Service project in Visual Studio.

  1. Open Visual Studio as administrator from Start | All Programs | Microsoft Visual Studio 2010 by right clicking the Microsoft Visual Studio 2010 shortcut and choosing Run as administrator.
  2. If the User Account Control dialog appears, click Yes.
  3. From the File menu, choose New and then Project.
  4. In the New Project dialog, expand the language of your preference (Visual C# or Visual Basic) in the Installed Templates list and select Cloud. Choose the Windows Azure Project template, set the Name of the project to GuestBook, set the location to \Source\Ex1-BuildingYourFirstWindowsAzureApp\[CS|VB], change the solution name to Begin, and ensure that Create directory for solution is checked. Click OK to create the project.

    Figure 1

    Creating a new Windows Azure Cloud Service project (C#)

    Figure 2

    Creating a new Windows Azure Cloud Service project (Visual Basic)

    Note:
     Windows Azure supports the .NET Framework 4.0. If you use Visual Studio 2010 to create the project, you can select this version for the target framework and take advantage of its new features.

  5. In the New Windows Azure Project dialog, inside the Roles panel, expand the tab for the language of your choice (Visual C# or Visual Basic), select ASP.NET Web Role from the list of available roles and click the arrow (>) to add an instance of this role to the solution. Before closing the dialog, select the new role in the right panel, click the pencil icon and rename the role as GuestBook_WebRole. Click OK to create the cloud service solution.

    Figure 3

    Assigning roles to the cloud service project (C#)

    Figure 4

    Assigning roles to the cloud service project (Visual Basic)

  6. In Solution Explorer, review the structure of the created solution.

    Figure 5

    Solution Explorer showing the GuestBook application (C#)

    Figure 6

    Solution Explorer showing the GuestBook application (Visual Basic)

    Note:
    The generated solution contains two separate projects. The first project, named GuestBook, holds the configuration for the web and worker roles that compose the cloud application. It includes the service definition file, ServiceDefinition.csdef, which contains metadata needed by the Windows Azure fabric to understand the requirements of your application, such as which roles are used, their trust level, the endpoints exposed by each role, the local storage requirements and the certificates used by the roles. The service definition also establishes configuration settings specific to the application. The service configuration files specify the number of instances to run for each role and sets the value of configuration settings defined in the service definition file. This separation between service definition and configuration allows you to update the settings of a running application by uploading a new service configuration file.You can create many configuration files, each one intended for a specific scenario such as production, development, or QA, and select which to use when publishing the application. By default, Visual Studio creates two files ServiceConfiguration.Local.cscfg and ServiceConfiguration.Cloud.cscfg.

    The Roles node in the cloud service project enables you to configure what roles the service includes (web, worker or both) as well as which projects to associate with these roles. Adding and configuring roles through the Roles node will update the ServiceDefinition.csdef and ServiceConfiguration.cscfg files.

    The second project, named GuestBook_WebRole, is a standard ASP.NET Web Application project template modified for the Windows Azure environment. It contains an additional class that provides the entry point for the web role and contains methods to manage the initialization, starting, and stopping of the role.

Task 2 – Creating a Data Model for Entities in Table Storage

The application stores guest book entries in Windows Azure Table storage. The Table service offers semi-structured storage in the form of tables that contain collections of entities. Entities have a primary key and a set of properties, where a property is a name, typed-value pair.

In addition to the properties required by your model, every entity in Table Storage has two key properties: the PartitionKey and the RowKey. These properties together form the table's primary key and uniquely identify each entity in the table. Entities also have a Timestamp system property, which allows the service to keep track of when an entity was last modified. This field is intended for system use and should not be accessed by the application. The Table Storage client API provides a TableServiceEntity class that defines the necessary properties. Although you can use the TableServiceEntity class as the base class for your entities, this is not required.

The Table service API is compliant with the REST API provided by WCF Data Services (formerly ADO.NET Data Services Framework) allowing you to use the WCF Data Services Client Library (formerly .NET Client Library) to work with data in Table Storage using .NET objects.

The Table service does not enforce any schema for tables making it possible for two entities in the same table to have different sets of properties. Nevertheless, the GuestBook application uses a fixed schema to store its data.

In order to use the WCF Data Services Client Library to access data in table storage, you need to create a context class that derives from TableServiceContext, which itself derives from DataServiceContext in WCF Data Services. The Table Storage API allows applications to create the tables that they use from these context classes. For this to happen, the context class must expose each required table as a property of type IQueryable<SchemaClass>, where SchemaClass is the class that models the entities stored in the table.

In this task, you model the schema of the entities stored by the GuestBook application and create a context class to use WCF Data Services to access the information in table storage. To complete the task, you create an object that can be data bound to data controls in ASP.NET and implements the basic data access operations: read, update, and delete.

  1. Create a new project for the schema classes. To create the project, in the File menu, point to Add and then select New Project.
  2. In the Add New Project dialog, expand the language of your choice under the Installed Templates tree view, select the Windows category, and then choose the Class Library project template. Set the name to GuestBook_Data, leave the proposed location inside the solution folder unchanged, and then click OK.

    Figure 7

    Creating a class library for GuestBook entities (C#)

    Figure 8

    Creating a class library for GuestBook entities (Visual Basic)

  3. Delete the default class file generated by the class library template. To do this, right-click Class1.cs (for Visual C# Projects) or Class1.vb (for Visual Basic Projects) and choose Delete. Click OK in the confirmation dialog.
  4. Add a reference to the .NET Client Library for WCF Data Services in the GuestBook_Data project. In Solution Explorer, right-click the GuestBook_Data project node, select Add Reference, click the .NET tab, select the System.Data.Services.Client component and click OK.

    Figure 9

    Adding a reference to the System.Data.Service.Client component

  5. Repeat the previous step to add a reference to the Windows Azure storage client API assembly, this time choosing the Microsoft.WindowsAzure.StorageClient component instead.
  6. Before you can store an entity in a table, you must first define its schema. To do this, right-click GuestBook_Data in Solution Explorer, point to Add and select Class. In the Add New Item dialog, set the name to GuestBookEntry.cs (for Visual C# projects) or GuestBookEntry.vb (for Visual Basic projects) and click Add.

    Figure 10

    Adding the GuestBookEntry class (C#)

    Figure 11

    Adding the GuestBookEntry class (Visual Basic)

  7. At the top of the file, insert the following namespace declaration to import the types contained in the Microsoft.WindowsAzure.StorageClient namespace.

    C#

    using Microsoft.WindowsAzure.StorageClient;

    Visual Basic

    Imports Microsoft.WindowsAzure.StorageClient

  8. If not already opened, open the GuestBookEntry.cs file (for Visual C# projects) or GuestBookEntry.vb file (for Visual Basic projects) and then update the declaration of the GuestBookEntry class to make it public and derive from the TableServiceEntity class.

    Note:
    In Visual Basic, the template for a new class already declares the class as Public.

    C#

    public class GuestBookEntry : Microsoft.WindowsAzure.StorageClient.TableServiceEntity
    {
    FakePre-4639e149366a4c86ae184eef409e72ff-d3676cc5dcf34c7c8c1a9e774d634dca

    Visual Basic

    Public Class GuestBookEntry Inherits Microsoft.WindowsAzure.StorageClient.TableServiceEntity
    FakePre-926c144f2e5c4e36ac301e3ec9987ea1-5652f9fb6e45412082553319013b9c46
    

    Note:
    TableServiceEntity is a class found in the Storage Client API. This class defines the PartititionKey, RowKey and TimeStamp system properties required by every entity stored in a Windows Azure table.

    Together, the PartitionKey and RowKey define the DataServiceKey that uniquely identifies every entity within a table.

  9. Add a default constructor to the GuestBookEntry class that initializes its PartitionKey and RowKey properties.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookEntry constructor – CS)

    C#

    public GuestBookEntry() { PartitionKey = DateTime.UtcNow.ToString("MMddyyyy"); // Row key allows sorting, so we make sure the rows come back in time order. RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid()); }

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookEntry constructor – VB)

    Visual Basic

    Public Sub New() PartitionKey = DateTime.UtcNow.ToString("MMddyyyy") ' Row key allows sorting, so we make sure the rows come back in time order. RowKey = String.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid()) End Sub

    Note:
    To partition the data, the GuestBook application uses the date of the entry as the PartitionKey, which means that there will be a separate partition for each day of guest book entries. In general, you choose the value of the partition key to ensure load balancing of the data across storage nodes.

    The RowKey is a reverse DateTime field with a GUID appended for uniqueness. Tables within partitions are sorted in RowKey order, so this will sort the tables into the correct order to be shown on the home page, with the newest entry shown at the top.

  10. To complete the definition of the GuestBookEntry class, add properties for Message, GuestName, PhotoUrl, and ThumbnailUrl to hold information about the entry.

    (Code Snippet – Introduction to Windows Azure - Ex1 Table Schema Properties – CS)

    C#

    public string Message { get; set; } public string GuestName { get; set; } public string PhotoUrl { get; set; } public string ThumbnailUrl { get; set; }

    (Code Snippet – Introduction to Windows Azure - Ex1 Table Schema Properties – VB)

    Visual Basic

    Public Property Message As String Public Property GuestName As String Public Property PhotoUrl As String Public Property ThumbnailUrl As String

  11. Save the GuestBookEntry.cs file (for Visual C# projects) or GuestBookEntry.vb file (for Visual Basic projects).
  12. Next, you need to create the context class required to access the GuestBook table using WCF Data Services. To do this, in Solution Explorer, right-click the GuestBook_Data project, point to Add and select Class. In the Add New Item dialog, set the Name to GuestBookDataContext.cs (for Visual C# projects) or GuestBookDataContext.vb (for Visual Basic projects) and click Add.
  13. In the new class file, update the declaration of the new class to make it public and inherit the TableServiceContext class.

    Note:
    In Visual Basic, the template for a new class already declares the class as Public.

    C#

    public class GuestBookDataContext : Microsoft.WindowsAzure.StorageClient.TableServiceContext
    {
    FakePre-1456bd307f274b51a9dcbffc7705ff02-21076a5b7499488f8536393e3f8adfef

    Visual Basic

    Public Class GuestBookDataContext Inherits Microsoft.WindowsAzure.StorageClient.TableServiceContext
    End Class

  14. Now, add a default constructor to initialize the base class with storage account information.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataContext Class – CS)

    C#

    public class GuestBookDataContext 
    FakePre-5c42864c905f48ce9d6444a4bf5f27fc-0b4dda686e6d4a76ac46c5a317582f9cFakePre-bbe0e8209e0a4bc1903102f6af4803ca-edb5c75dc1ee418eb0a5fd635090b056 public GuestBookDataContext(string baseAddress, Microsoft.WindowsAzure.StorageCredentials credentials) : base(baseAddress, credentials) { }FakePre-79bc0ea8af404943a4813c7184a7783a-4ebd264ba3284ed1ab67c06ee5bbc79b

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataContext Class – VB)

    Visual Basic

    Public Class GuestBookDataContext
    FakePre-0d89eb9c4ee44ce2b0b2c5102f67628a-8377f0c23d584ada9b9384ad45f26d42FakePre-909fa19b1ecd4179bcf552633b1578eb-357195b3e6974f468cc16d281c182593 Public Sub New(ByVal baseAddress As String, ByVal credentials As Microsoft.WindowsAzure.StorageCredentials) MyBase.New(baseAddress, credentials) End SubFakePre-1a58c69fca6742c79f30bb5796644702-a4766fccda1a42f4854236ca60ea3eb8

    Note:
    You can find the TableServiceContext class in the storage client API. This class derives from DataServiceContext in WCF Data Services and manages the credentials required to access your storage account as well as providing support for a retry policy for its operations.

  15. Add a property to the GuestBookDataContext class to expose the GuestBookEntry table. To do this, insert the following (highlighted) code into the class.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookEntry Property – CS)

    C#

    public class GuestBookDataContext 
    FakePre-8e6d1243c67b438ca7fc3b30908f6468-5de0744891434db68fdc140992f7b071FakePre-93eb96b903fc4347bc0735ce977fc455-8f84db0a535a488fa583e0c5b70046c9FakePre-7324377c593d4b339d85cf2ee392c12a-358148cdbfc543bd8fd527fa2909dcae public IQueryable<GuestBookEntry> GuestBookEntry { get { return this.CreateQuery<GuestBookEntry>("GuestBookEntry"); } }FakePre-32005e45a1034f3695a6c42c4fa2fd21-5f97c7e4e57d465facc02e2b856637bd

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookEntry Property – VB)

    Visual Basic

    Public Class GuestBookDataContext
    FakePre-ab1c43755c1245dcb02be68784fd9dc6-938034fc201f41d5805c92095a5386d1FakePre-98cd61085e3f4d2fae8be38658099617-4b69a635ce524b11874aa5511ff13720 Public ReadOnly Property GuestBookEntry() As IQueryable(Of GuestBookEntry) Get Return Me.CreateQuery(Of GuestBookEntry)("GuestBookEntry") End Get End PropertyFakePre-937caac4f72540d5a2148b6cc79591be-5c5728bbd9de4c8c9cfe427b31c9dc25

    Note:
    You can use the CreateTablesFromModel method in the CloudTableClient class to create the tables needed by the application. When you supply a DataServiceContext (or TableServiceContext) derived class to this method, it locates any properties that return an IQueryable<T>, where the generic parameter T identifies the class that models the table schema, and creates a table in storage named after the property.

  16. Finally, you need to implement an object that can be bound to data controls in ASP.NET. In Solution Explorer, right-click GuestBook_Data, point to Add, and select Class. In the Add New Item dialog, set the name to GuestBookDataSource.cs (for Visual C# projects) or GuestBookDataSource.vb (for Visual Basic projects) and click Add.
  17. In the new class file, add the following namespace declarations to import the types contained in the Microsoft.WindowsAzure and Microsoft.WindowsAzure.StorageClient namespaces.

    C#

    using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.StorageClient;

    Visual Basic

    Imports Microsoft.WindowsAzure Imports Microsoft.WindowsAzure.StorageClient

  18. In the GuestBookDataSource class, make the class public and define member fields for the data context and the storage account information, as shown below.

    Note:
    In Visual Basic, the template for a new class already declares the class as Public.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Fields – CS)

    C#

    public class GuestBookDataSource
    FakePre-81a460c49c764b0d9382df7923639553-5b5f9de0d66245749077c58169731a21 private static CloudStorageAccount storageAccount; private GuestBookDataContext context;FakePre-0a3f69549ee04ae4a85ddd8a90a662d0-48c80e0c99834e62acb2eb1f72a9f7d1

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Fields – VB)

    Visual Basic

    Public Class GuestBookDataSource
    FakePre-a569da7af40b41b29bc80a2fcb73a966-b912aa4c18524259b8cddc62d4bb2ffe Private Shared storageAccount As CloudStorageAccount Private context As GuestBookDataContextFakePre-0aec33c78b804ecc992447a18f4f803b-45d1417e80824550989f91f17d0c8036

  19. Now, add a static (Shared in Visual Basic) constructor to the data source class as shown in the following (highlighted) code. This code creates the tables from the GuestBookDataContext class.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Static Constructor – CS)

    C#

    public class GuestBookDataSource
    FakePre-217f6727f58b4fdfa69756addce152bf-f758a899b0f146009c4b3d02ef772bd9FakePre-5e101363968b4e7c862ca3ae77cfd5ad-5e7424fbcbe640a8945a0f0aa72e8379 static GuestBookDataSource() { storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString"); CloudTableClient.CreateTablesFromModel( typeof(GuestBookDataContext), storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials); }FakePre-b974e1a38d2647e49864063355d25843-23e968187ff7492eb5acb1844d50c93eFakePre-353bf0fae72045d9aa1230f0f1b08529-d4ae5761acae43e7add2b2e7d5c2657d

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Shared Constructor – VB)

    Visual Basic

    Public Class GuestBookDataSource
    FakePre-832adeb228ac4676a75f05e15818f8da-bc87102a9594491d8d144934d5a75fc0 Shared Sub New() storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString") CloudTableClient.CreateTablesFromModel(GetType(GuestBookDataContext), storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials) End SubFakePre-08f6e212c6334758a4d22aa2a90d88dd-9e5083cb038846998f06b2ca234eeb56FakePre-b2ecf2e833884978a7378ffdc220883f-a8f447788616416fb76bf62b486bc046

    Note:
    The static (Shared in Visual Basic) constructor initializes the storage account by reading its settings from the configuration and then uses the CreateTablesFromModel method in the CloudTableClient class to create the tables used by the application from the model defined by the GuestBookDataContext class. By using the static constructor, you ensure that this initialization task is executed only once.

  20. Add a default constructor to the GuestBookDataSource class to initialize the data context class used to access table storage.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Constructor – CS)

    C#

    public class GuestBookDataSource
    FakePre-3bc3038123904972ad18d2469912a32a-de2c1326b3c84f9d95bc0a897fbd87eeFakePre-be9c9431459f4f969263cff6100a91fa-df5bacd44b8847cebb2f539a4c426e16 public GuestBookDataSource() { this.context = new GuestBookDataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials); this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1)); }FakePre-6e7a65ad02fe4792be2cc73b2d597471-4fe53651c7dd4b39a200d7cf3c7cebde

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Constructor – VB)

    Visual Basic

    Public Class GuestBookDataSource
    FakePre-5c399f771e8c48dfa2288b17898e647a-300e0cf6c6c948eca52974927c3a080a Public Sub New() Me.context = New GuestBookDataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials) Me.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1)) End SubFakePre-a18f087caf634bf8b2e41ee0dad4a134-b99623b29d1b464ba1282ec71868b6fd

  21. Next, insert the following method to return the contents of the GuestBookEntry table.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Select – CS)

    C#

    public class GuestBookDataSource
    FakePre-f9bd372a13594cd9b6f9c7269709d6a1-8e357bf1b0e646ef89b4f57a3d19bd61FakePre-f8abc6f73259450f872327525fa96ca2-5a7c2b282d7340ed8a991dc62e2f9da0 public IEnumerable<GuestBookEntry> GetGuestBookEntries() { var results = from g in this.context.GuestBookEntry where g.PartitionKey == DateTime.UtcNow.ToString("MMddyyyy") select g; return results; }FakePre-200d1f4c00a54de990e8a89bb2cc6555-9e4d97da2c0c4cda95f04f642d06f000

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource Select – VB)

    Visual Basic

    Public Class GuestBookDataSource
    FakePre-f485051691234899b565235dd72d84b4-8a901da6e53b491fb8a2d0dd9dcfd527 Public Function GetGuestBookEntries() As IEnumerable(Of GuestBookEntry) Dim results = From g In Me.context.GuestBookEntry _ Where g.PartitionKey = DateTime.UtcNow.ToString("MMddyyyy") _ Select g Return results End FunctionFakePre-effd4b433fc84b0cb028b65cd689ed2c-a17d5950200546ce9f8c3c123ea5e45d

    Note:
    The GetGuestBookEntries method retrieves today's guest book entries by constructing a LINQ statement that filters the retrieved information using the current date as the partition key value. The web role uses this method to bind to a data grid and display the guest book.

  22. Now, add the following method to insert new entries into the GuestBookEntry table.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource AddGuestBookEntry – CS)

    C#

    public class GuestBookDataSource
    FakePre-a995e2ebb0974ef5a43936149c060e32-9f865910944e4a69a9b7e9fa4c8fcb08FakePre-01b2c63385504de5a8ab24a8495af71f-6578f27674034b9d9db4a014b3e4ab6e public void AddGuestBookEntry(GuestBookEntry newItem) { this.context.AddObject("GuestBookEntry", newItem); this.context.SaveChanges(); }FakePre-3ff4a3cc8ae945e993e32564e23cb50e-db55653e6f96486a816c9ac41f19f8c5

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource AddGuestBookEntry – VB)

    Visual Basic

    Public Class GuestBookDataSource
    FakePre-abbee311139c440aa6a040fc91d5d847-696dda7acc2843b4ad6d74776ce3d6f0 Public Sub AddGuestBookEntry(ByVal newItem As GuestBookEntry) Me.context.AddObject("GuestBookEntry", newItem) Me.context.SaveChanges() End SubFakePre-0fadf918f3984abeb8136ab2f7534b03-dbfc075e49ac4223b7a1436004ddc8b6

    Note:
    This method adds a new GuestBookEntry object to the data context and then calls SaveChanges to write the entity to storage.

  23. Finally, add a method to the data source class to update the thumbnail URL property for an entry.

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource UpdateImageThumbnail – CS)

    C#

    public class GuestBookDataSource
    FakePre-890fb08f49784c5a9972911d985951b2-196d687958184ee89374ee29ef023cb9FakePre-5fba3534c7944d3c8ecaaae832015424-056a0771edf44f44810f5868b3839f1e public void UpdateImageThumbnail(string partitionKey, string rowKey, string thumbUrl) { var results = from g in this.context.GuestBookEntry where g.PartitionKey == partitionKey && g.RowKey == rowKey select g; var entry = results.FirstOrDefault<GuestBookEntry>(); entry.ThumbnailUrl = thumbUrl; this.context.UpdateObject(entry); this.context.SaveChanges(); }FakePre-0d29c983680b4a0eae925c86a8d0135a-3e50071063034b2d9b3facc0d5d2ba0bFakePre-97419d0c59574ef3b2b53f225c3211f3-8d84376d4abe4caebcfa8f268b4e1028FakePre-4f94618353484c6984c41bd36104ccb2-380fbd21bb24456ea641d2921937df5a

    (Code Snippet – Introduction to Windows Azure - Ex1 GuestBookDataSource UpdateImageThumbnail – VB)

    Visual Basic

    Public Class GuestBookDataSource
    FakePre-34e9559d201f480b86ef8f09266e9e6b-f7b10d56a5434268a5a3d5d0fca3af1a Public Sub UpdateImageThumbnail(ByVal partitionKey As String, ByVal rowKey As String, ByVal thumbUrl As String) Dim results = From g In Me.context.GuestBookEntry _ Where g.PartitionKey = partitionKey AndAlso g.RowKey = rowKey _ Select g Dim entry = results.FirstOrDefault() entry.ThumbnailUrl = thumbUrl Me.context.UpdateObject(entry) Me.context.SaveChanges() End SubFakePre-45e282679fa542d5b540e4a13ebebb2f-60ce9a576e744f4d9a4182b4d4120467FakePre-a4479bd017004f8d81a8d0adbd688fbe-591e0b1c18fe453b8053d4b574276e22

    Note:
    The UpdateImageThumbnail method locates an entry using its partition key and row key; it updates the thumbnail URL, notifies the data context of the update, and then saves the changes.

  24. Save the GuestBookDataSource.cs file (for Visual C# projects) or GuestBookDataSource.vb file (for Visual Basic projects).

Task 3 – Creating a Web Role to Display the Guest Book and Process User Input

In this task, you update the web role project that you generated in Task 1, when you created the Windows Azure Cloud Service solution. This involves updating the UI to render the list of guest book entries. For this purpose, you will find a page that has the necessary elements in the Assets folder of this exercise, which you will add to the project. Next, you implement the code necessary to store submitted entries in table storage and images in blob storage. To complete this task, you configure the storage account used by the Web role.

  1. Add a reference in the web role to the GuestBook_Data project. In Solution Explorer, right-click the GuestBook_WebRole project node and select Add Reference, switch to the Projects tab, select the GuestBook_Data project, and then click then OK.
  2. The web role template generates a default page. You will replace it with another page that contains the UI of the guest book application. To delete the page, in Solution Explorer, right-click Default.aspx in the GuestBook_WebRole project and select Delete.
  3. Add the main page and its associated assets to the web role. To do this, right-click GuestBook_WebRole in Solution Explorer, point to Add and select Existing Item. In the Add Existing Item dialog, browse to the Assets folder in \Source\Ex1-BuildingYourFirstWindowsAzureApp for the language of your project (Visual C# or Visual Basic), hold the CTRL key down while you select every file in this folder and click Add.

    Note:
    The Assets folder contains five files that you need to add to the project, a Default.aspx file with its code-behind and designer files, a CSS file, and an image file.

  4. Open the code-behind file for the main page in the GuestBook_WebRole project. To do this, right-click the Default.aspx file in Solution Explorer and select View Code.
  5. In the code-behind file, insert the following namespace declarations.

    (Code Snippet– Introduction to Windows Azure - Ex1 Web Role Namespace Declarations – CS)

    C#

    using System.IO; using System.Net; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient; using GuestBook_Data;

    (Code Snippet– Introduction to Windows Azure - Ex1 Web Role Namespace Declarations – VB)

    Visual Basic

    Imports System.IO Imports System.Net Imports Microsoft.WindowsAzure Imports Microsoft.WindowsAzure.ServiceRuntime Imports Microsoft.WindowsAzure.StorageClient Imports GuestBook_Data

  6. Declare the following member fields in the _Default class.

    (Code Snippet – Introduction to Windows Azure - Ex1 Web Role Member Fields – CS)

    C#

    public partial class _Default : System.Web.UI.Page
    FakePre-7624bfa5f6034deda4f179bd682d1e51-badaf5753f5849589838de3068f2d7b5 private static bool storageInitialized = false; private static object gate = new Object(); private static CloudBlobClient blobStorage;FakePre-f55b2c3c7bd246e9bd9b508bbe4a9993-0142a0af48fa4280968b352fb09d2e0aFakePre-3f76801a62464dc39dcb678bc3d2f737-c599066013ef4a9093a54c85a48749b9FakePre-9c351df51ad045d39256ffd29b063b8c-daa6c864c3e64f23add6cb4806714957

    (Code Snippet – Introduction to Windows Azure - Ex1 Web Role Member Fields – VB)

    Visual Basic

    Partial Public Class _Default
    FakePre-b260248a203b47f380aa196bcc338f5b-6a7d2ce28f7f4b75b3a75b3072896d7eFakePre-0583de0098d74f9389a8b17bb7f54c20-9f3f1d59e8cb4c51b6494d1160102def Private Shared storageInitialized As Boolean = False Private Shared gate As New Object() Private Shared blobStorage As CloudBlobClientFakePre-cab0001e6c1044e88208a396b289875c-ab156ad9b16b4fcaba4b11683ea91f27FakePre-27c12f394c47462b9d926f26219a503c-eecf0ec25f8240b2a5339f970986724bFakePre-94e06291faef47a7941098cb664239a9-0b84f7b6c5a14fec87da912720cf90f4

  7. Locate the SignButton_Click event handler in the code-behind file and insert the following code.

    (Code Snippet– Introduction to Windows Azure - Ex1 SignButton_Click – CS)

    C#

    public partial class _Default : System.Web.UI.Page
    FakePre-ef8611c50f664f48ba9c739549f9cde7-cfdeb9301c2944c985d54b5792dc9f97FakePre-0d991ac1369e4dda8c50640a5cdd28d7-5a64497a3922446d839c410f31163c34FakePre-3fdc09ccc02b43dd9ec2f317ec7128e1-f27b5c7c6c1c41e6bdd1e0deda8b9d91FakePre-bc4d060551ad40828f06f55439b2f269-d8804627e010495d99fc8e07def84a6e if (FileUpload1.HasFile) { InitializeStorage(); // upload the image to blob storage string uniqueBlobName = string.Format("guestbookpics/image_{0}{1}", Guid.NewGuid().ToString(), Path.GetExtension(FileUpload1.FileName)); CloudBlockBlob blob = blobStorage.GetBlockBlobReference(uniqueBlobName); blob.Properties.ContentType = FileUpload1.PostedFile.ContentType; blob.UploadFromStream(FileUpload1.FileContent); System.Diagnostics.Trace.TraceInformation("Uploaded image '{0}' to blob storage as '{1}'", FileUpload1.FileName, uniqueBlobName); // create a new entry in table storage GuestBookEntry entry = new GuestBookEntry() { GuestName = NameTextBox.Text, Message = MessageTextBox.Text, PhotoUrl = blob.Uri.ToString(), ThumbnailUrl = blob.Uri.ToString() }; GuestBookDataSource ds = new GuestBookDataSource(); ds.AddGuestBookEntry(entry); System.Diagnostics.Trace.TraceInformation("Added entry {0}-{1} in table storage for guest '{2}'", entry.PartitionKey, entry.RowKey, entry.GuestName); } NameTextBox.Text = ""; MessageTextBox.Text = ""; DataList1.DataBind();FakePre-4e319c5f7c144fde9c3e74890d939f5f-d85d82e3e792488e83f2c0e1c9e7b51dFakePre-8b4b14be1c794ca4a8c5000338982acb-20570a3161044c1facb4463ed822d300FakePre-3064f9ebbe8c47a293d4b1b381688ecb-7fe66a855a2e42dabf4a7abb90ccb24fFakePre-367fa752d1a64a298185b2179d3b340b-b22d74208f3a4c918b411a1cf3c594eaFakePre-24fc3ad6426841a6921ad84fedd2c221-05e2e9b9472c4fecbe065192fa10ce27FakePre-84819cb8646a4c9fb92334d5c3c99b01-53632819540149249f976936c4c77f50

    (Code Snippet – Introduction to Windows Azure - Ex1 SignButton_Click – VB)

    Visual Basic

    Public Class _Default
    FakePre-b9ee7c0c66db4a15bb85e4cc73c94b1f-63260abb6fbb47049b87cabf2a178190FakePre-a68cb5586e214d08822d9c07c3598464-1194340849f1472281f61dd0cec75403FakePre-4807707430954561b7adfaf2cc307fde-c8a1c8d2756c4728a40897593efb20adFakePre-326b634714b846459f566bd861ca4804-dfa90ed4534a4560882b74a639601108 If FileUpload1.HasFile Then InitializeStorage() ' upload the image to blob storage Dim uniqueBlobName As String = String.Format("guestbookpics/image_{0}{1}", Guid.NewGuid().ToString(), Path.GetExtension(FileUpload1.FileName)) Dim blob As CloudBlockBlob = blobStorage.GetBlockBlobReference(uniqueBlobName) blob.Properties.ContentType = FileUpload1.PostedFile.ContentType blob.UploadFromStream(FileUpload1.FileContent) System.Diagnostics.Trace.TraceInformation("Uploaded image '{0}' to blob storage as '{1}'", FileUpload1.FileName, uniqueBlobName) ' create a new entry in table storage Dim entry As New GuestBookEntry() With {.GuestName = NameTextBox.Text, .Message = MessageTextBox.Text, .PhotoUrl = blob.Uri.ToString(), .ThumbnailUrl = blob.Uri.ToString()} Dim ds As New GuestBookDataSource() ds.AddGuestBookEntry(entry) System.Diagnostics.Trace.TraceInformation("Added entry {0}-{1} in table storage for guest '{2}'", entry.PartitionKey, entry.RowKey, entry.GuestName) End If NameTextBox.Text = "" MessageTextBox.Text = "" DataList1.DataBind()FakePre-50315888bb984bce8dd9fab567f51514-7d2201760fd04a278b1bb5dfce3485baFakePre-41f1e468b33a441b930d9f7a0cdcada3-16dc5b315a2e4e19b698d0d884d9dd6aFakePre-7fa6b86f6558405e94bb9fd4aafb7628-3ffc55459207467d803a28bdfb98dcd1FakePre-99d01de1f0074d828b063efe288e2574-fe0254c8df434983b2e3d7eef3bf7d34FakePre-86ae759302464fd085392d0d2a051829-f30721f4b91e4f47a94fadd57a9ebfd1FakePre-621a49dba9b648aba30c834c5a6e3ebb-159b48bf1e6747929cf63091dcfc4b80

    Note:
    To process a new guest book entry after the user submits the page, the handler first calls the InitializeStorage method to ensure that the blob container used to store images exists and allows public access. You will implement this method shortly.

    It then obtains a reference to the blob container, generates a unique name and creates a new blob, and then uploads the image submitted by the user into this blob. Notice that the method initializes the ContentType property of the blob from the content type of the file submitted by the user. When the guest book page reads the blob back from storage, the response returns this content type, allowing a page to display the image contained in the blob simply by referring to its URL.

    After that, it creates a new GuestBookEntry entity, which is the entity you defined in the previous task, initializes it with the information submitted by the user, and then uses the GuestBookDataSource class to save the entry to table storage using the .NET Client Library for WCF Data Services.

    Finally, it data binds the guest book entries list to refresh its contents.

  8. Update the body of the Timer1_Tick method with the code shown below.

    (Code Snippet– Introduction to Windows Azure - Ex1 Timer1_Tick – CS)

    C#

    public partial class _Default : System.Web.UI.Page
    FakePre-c11cec1c26154904b439522aac3cbbed-b697eb6af079482c989490e629e65507FakePre-3dbd07cf79dd4595bc4e6442638d587b-818140e2cc3548a09404e72d4b190c7dFakePre-531475852e8d48218fd34b93632e3bbc-c90608664c904b1e8c75e812cf3083e8FakePre-830affd5158c4f8faf4806f377892f6a-3fbe6aed14a94d0999dcca6095f0eba9 DataList1.DataBind();FakePre-7a7f3da1ba9f409798815fa7ba5b8440-368effe427f545298021e6b7b400cb16FakePre-8f2cd3f0931a434eab223df7a600dc62-13a3540335664a80bf8f51060f8861e2

    (Code Snippet – Introduction to Windows Azure - Ex1 Timer1_Tick – VB)

    Visual Basic

    Public Class _Default
    FakePre-2794c5487340481a93a90171f0db2ac4-b4e8103e4de44a65b9c79e714e689d2fFakePre-b390605d71b14721b06994854b955130-e9753c0628d343a19ec0bc92e58b61f7FakePre-484e1e55f3a843108a2c1a5647d2ad81-cc5f670f5a474e3189e2f6dc8c5e2ea1 DataList1.DataBind()FakePre-c682c39c583c43cea8f30df2d0295233-ad7f88a732254da99e59bc9c7f8b1a35FakePre-bd96342f80fe45ab91ae142c67541468-f748a3416f60427293b0158ac818b0e8

    Note:
    The timer periodically forces the page to refresh the contents of the guest book entries list.

  9. Locate the Page_Load event handler and update its body with the following code to enable the page refresh timer.

    (Code Snippet – Introduction to Windows Azure - Ex1 Page_Load – CS)

    C#

    public partial class _Default : System.Web.UI.Page
    FakePre-f997c08d92954787bac568e778ae098c-12d0a4af08c945ce8374029fc3c93ac5FakePre-f6cd888ee53141ecbddad66baba3bd25-f290addf78154ed28f74996c2a3d0365FakePre-a7455329555d422190881497d5a9f07e-35634d2a0bb34090813f85325ea4eda3FakePre-cca855ca700a4dfe88bbb6301b30288c-0c08040a59944314af3a8ae6aa3cbea7 if (!Page.IsPostBack) { Timer1.Enabled = true; }FakePre-645208c2285f45ebaef15194d99d646f-652f592da91f4362b3368ef5802394d2FakePre-69162b5d24dd4d12a7a08060ecde00b5-680b1cbc6e404c8db3b1ae98ae80f3cf

    (Code Snippet – Introduction to Windows Azure - Ex1 Page_Load – VB)

    Visual Basic

    Public Class _Default
    FakePre-9baa663d3b434b0eb865f83226661ea1-fc3df5cfe1834c7e88b1db95150b2f2aFakePre-b8398b8758fe439199f06c069045d740-a1637369d6c44130adca4dcd3da8dde2FakePre-4f943df884cb4b3a911be50ffa6af3cc-2d660f248d684ebc9758d3e5b73431ca If Not (Page.IsPostBack) Then Timer1.Enabled = True End IfFakePre-421f1490d487419ca861d6ad21c6f993-6adb2091242c4fe495e90e3a07d47008FakePre-8b1b645e55014f96a8a33b75d95fb1e8-3bceda5b127147a2a63ff16ac8c49207

  10. Implement the InitializeStorage method by replacing its body with the following (highlighted) code.

    (Code Snippet – Introduction to Windows Azure - Ex1 InitializeStorage – CS)

    C#

    public partial class _Default : System.Web.UI.Page
    FakePre-ee25da55661d471f855e1bd6bd5c4ba7-cb578fb32b6e49729126c0ba14865ca4FakePre-cb28a859f11e41eb8f39c58b53a91518-1cf32978a527492abdd51c44ae832fc1FakePre-bec3a6c8a0074159b37fc44d6fa0daac-897830ec2db443a49f66832b25c65398FakePre-62b3e5524fc34f788deadf714d5bd614-29f5cbe6cdf04b15854a274edfb3af6c if (storageInitialized) { return; } lock (gate) { if (storageInitialized) { return; } try { // read account configuration settings var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString"); // create blob container for images blobStorage = storageAccount.CreateCloudBlobClient(); CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics"); container.CreateIfNotExist(); // configure container for public access var permissions = container.GetPermissions(); permissions.PublicAccess = BlobContainerPublicAccessType.Container; container.SetPermissions(permissions); } catch (WebException) { throw new WebException("Storage services initialization failure. " + "Check your storage account configuration settings. If running locally, " + "ensure that the Development Storage service is running."); } storageInitialized = true; }FakePre-d83c384e93b44ba59847f27611723967-fea673a1436d48b29a13e06554faca5cFakePre-56b864fe14f044f7916595aa2ada310f-dd85f429f5804f85be9c1735477189adFakePre-f2d7f465c6ed4a70ae5e59c7b7c54fbb-f520b57d050e4eb4891462a1710b50dbFakePre-919b75148b84444da1b6f6181113b5e1-6caa94e756964f4d93c4ef94b074a277FakePre-966fbbff42e94669b94fa8fef16c2aab-e8cb0ac6b0454f12bd7f086da6264302FakePre-db3f79c237ec44e0aa0ab5b08c0bb463-733881e80db64bc9a58297cbd997c1dfFakePre-6eca6a497fcd4ba8bf7ccb180c2ca916-1af0683c6dac42f4a4e55e75dd5f79f5

    (Code Snippet – Introduction to Windows Azure - Ex1 InitializeStorage – VB)

    Visual Basic

    Public Class _Default
    FakePre-511852e776f8472f99dfcd6dc53e1a4b-103e1647429043d38983e0fa68c9deaaFakePre-b708649e29334411974099e23aada915-b38f6feb86c94b1487398b03b3b7140fFakePre-9cf5cc63575e40149a8c84fdc45298f2-685697be12634eca8ce026564a38aba8 If storageInitialized Then Return End If SyncLock gate If storageInitialized Then Return End If Try ' read account configuration settings Dim storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString") ' create blob container for images blobStorage = storageAccount.CreateCloudBlobClient() Dim container As CloudBlobContainer = blobStorage.GetContainerReference("guestbookpics") container.CreateIfNotExist() ' configure container for public access Dim permissions = container.GetPermissions() permissions.PublicAccess = BlobContainerPublicAccessType.Container container.SetPermissions(permissions) Catch e1 As WebException Throw New WebException("Storage services initialization failure. " _ & "Check your storage account configuration settings. If running locally, " _ & "ensure that the Development Storage service is running.") End Try storageInitialized = True End SyncLockFakePre-6d87541df23a437d981fe65a51c5dcfe-acd7cd3de73648ccb3c6c5c96ca03de6FakePre-c6fb4a26f169471994a5a20d92c625e5-8f44c950e0594539aa5280f74ce29534FakePre-f8dbe2c312e54f918d016e897663e93c-8f02cd2a174f441e8d7075be453bf201FakePre-f56e4f4096ae4ffc929c40379e7406f5-380ce9c6f0be4121be4b157eea6c2266FakePre-15c54e61def74df2a1242c36a4081370-77cb17284bef4b99865abdbbe9ac6dd4FakePre-f569050748314545b646936b137a5f97-8af5fe74930f4d7a979b2edac3384fd4

    Note:
    The InitializeStorage method first ensures that it executes only once. It reads the storage account settings from the Web role configuration, creates a blob container for the images uploaded with each guest book entry and configures it for public access.

  11. Because the web role uses Windows Azure storage services, you need to provide your storage account settings. To create a new setting, in Solution Explorer, expand the Roles node in the GuestBook project, double-click GuestBook_WebRole to open the properties for this role and select the Settings tab. Click Add Setting, type “DataConnectionString” in the Name column, change the Type to ConnectionString, and then click the button labeled with an ellipsis.

    Figure 12

    Configuring the storage account settings

  12. In the Storage Account Connection String dialog, choose the option labeled Use the Windows Azure storage emulator and then click OK.

    Figure 13

    Creating a connection string for the storage emulator

    Note:
    A storage account is a unique endpoint for the Windows Azure Blob, Queue, and Table services. You must create a storage account in the Management Portal to use these services. In this exercise, you use Windows Azure storage emulator, which is included in the Windows Azure SDK development environment to simulate the Blob, Queue, and Table services available in the cloud. If you are building a hosted service that employs storage services or writing any external application that calls storage services, you can test locally against the Windows Azure storage emulator.

    To use the storage emulator, you set the value of the UseDevelopmentStorage keyword in the connection string for the storage account to true. When you publish your application to Windows Azure, you need to update the connection string to specify storage account settings including your account name and shared key. For example,

    <Setting name="DataConnectionString" value="DefaultEndpointsProtocol=https;AccountName=YourAccountName;AccountKey=YourAccountKey" />

    where YourAccountName is the name of your Azure Storage account and YourAccountKey is your access key.

  13. Press CTRL + S to save changes to the role configuration.
  14. Finally, you need to set up the environment for the configuration publisher. In the GuestBook_WebRole project, open the Global.asax.cs file (for Visual C# projects) or the Global.asax.vb file (for Visual Basic projects).
  15. At the top of the file, insert the following namespace declaration to import the types contained in the Microsoft.WindowsAzure and Microsoft.WindowsAzure.ServiceRuntime namespaces.

    C#

    using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime;

    Visual Basic

    Imports Microsoft.WindowsAzure Imports Microsoft.WindowsAzure.ServiceRuntime

  16. Insert the following code into the Application_Start method replacing the default comment.

    (Code Snippet – Introduction to Windows Azure - Ex1 SetConfigurationSettingPublisher – CS)

    C#

    void Application_Start(object sender, EventArgs e)
    FakePre-81a8279263084a2fbb46e352f0d99b8c-93f9d9ff0d524cfe93f11a0816dca45dMicrosoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) => { configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)); });FakePre-3124ba504ff34ae0b1e7df8ef91bd803-ec0f7c31f7c247fbb613cbad0e35aa24

    (Code Snippet – Introduction to Windows Azure - Ex1 SetConfigurationSettingPublisher – VB)

    Visual Basic

    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
    CloudStorageAccount.SetConfigurationSettingPublisher(Function(configName, configSetter) configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))FakePre-4e9f5d76cab9430e95b6198b7a4ae81e-264a66c84f494bcbb351dab082317295

Task 4 – Queuing Work Items for Background Processing

In preparation for the next exercise, you now update the front-end web role to dispatch work items to an Azure queue for background processing. These work items will remain in the queue until you add a worker role that picks items from the queue and generates thumbnails for each uploaded image.

  1. Open the code-behind file for the main page of the web role project. To do this, right-click the Default.aspx file in Solution Explorer and select View Code.
  2. Declare a queue client member by inserting the following (highlighted) declaration into the Default class.

    (Code Snippet – Introduction to Windows Azure - Ex1 CloudQueueClient member – CS)

    C#

    public partial class _Default : System.Web.UI.Page
    FakePre-634afe35b27b418186871248e0e6cfb4-99396e8df7204822b12a77a43815b660FakePre-3e084a25c0014718860f51f52785fb22-26935c8ac6564bafb4b060a6ee24106aFakePre-9605bd7d9b844a63b4f1d26503d563c0-9e637703207a4821a9d23cd44f5cfd9cFakePre-f0e60cf2542149679b29d37d363efd6d-0a980ebf40b644b4ae1a2d864223d99b private static CloudQueueClient queueStorage;FakePre-3c08b867ab664f6f8891f2e8b9a4bd72-0276fb48e3214c718b8552bc4b02a9a0FakePre-26fa730c86664ff9a79413815ba82962-7b0c3da8133b4ba08fb4625c8160a965

    (Code Snippet – Introduction to Windows Azure - Ex1 CloudQueueClient member – VB)

    Visual Basic

    Public Class _Default
    FakePre-0443c6104e9a456cb1f48ffcde6f6b17-954a2f8bebd14889b27ed0b269741384FakePre-d1e5310f085540909e1e55b00da302f4-9f71e44ba81b49cfa4e22048336b1999FakePre-a70e64beb5674947aecc62358eff213b-5a832d8906114e50b0f70ff2b2fe7125FakePre-99cfc02137434934b9316bafc90f606d-bddc025081234c76bf5b9378673a376bFakePre-72a47cf63485458a915371291428b677-a7503a631e1a48a1a79f553a3261439f Private Shared queueStorage As CloudQueueClientFakePre-cf32d6fd88034c62b798c38c552e9977-18434d72366644e3901eea884a07e64fFakePre-82c529df29b44c54898185dc11e26feb-ec77b2a069964428abb6eeaebdd9bfa2

  3. Now, update the storage initialization code to create the queue, if it does not exist, and then initialize the queue reference created in the previous step. To do this, locate the InitializeStorage method and insert the following (highlighted) code into this method immediately after the code that configures the blob container for public access.

    (Code Snippet – Introduction to Windows Azure - Ex1 Create Queue – CS)

    C#

    public partial class _Default : System.Web.UI.Page
    FakePre-833914d91d5f4c78afa182c0b487de3b-56747ab0cccd4cffb2023fb4e565eb7dFakePre-c1d3e8a8c8544f79b55265a3ee91d604-37a5879d783d4423b6b69da02f6171e1FakePre-ee2b3624fab44a44be1b7eed675211d8-1c3394c0cfb64f12871685af3292558aFakePre-9a3a836c8274490e98260b5c5ca6294e-c686fd29b2ad41cdac6721e916154609FakePre-e906cf4c7de74c2fbe1edaabc11c0d2f-9d115c87a36447399195ec11cefa9c97FakePre-4e44df422b944ed0af39b6b925641ea3-6e9093d9ba954757890c447b0eefadbfFakePre-bf9ae21b3cdd4487b5b95f5342fbb73e-c75a1b1d8cda4112a18c68771f7c418fFakePre-6dbd61e9dc8140ab8303e519d16dc89f-b9c45f71cad5474fbe1783ec4a6cf746FakePre-da579de14fa0431495fdf81cc15511e4-87b577681a17412ca06f771f72dc6736FakePre-cb148e2ea13f425b81ff47a3f538dac9-0b5f7376ecf64c2bbb9ff4974ed5c6ceFakePre-587289fde93b4bcfa8fdb565dc9d8251-1e18f3c460584b9ba86d6eaebbf53a36FakePre-91baed820d634b3bacfd9a2b83dcd384-2c7ea248018c46fd9c7b9e39ef9cd6abFakePre-9b9e8159feef48e79a462aff5d3343c3-9e689cf563054ff7afdc6d09de99de37 // create queue to communicate with worker role queueStorage = storageAccount.CreateCloudQueueClient(); CloudQueue queue = queueStorage.GetQueueReference("guestthumbs"); queue.CreateIfNotExist();FakePre-f31259f3620344ad88f84e83ef4f2dd7-6ca2ab2007234850aca5dcafa4c5eae6FakePre-4468bc1560d140b7a0e852840e1f8bbf-a9fed8a6a2d34e609782cdc5d0c65826FakePre-98c3c49b7c074c8db0baea27144a334d-a47a6b799e1c45229706202f13dba521FakePre-850142cbe6a54a22b7b4b49c854a5507-e8854c83d6014bba8ca1721d7e6019a8FakePre-68f9d7790c50499d9b337bd1a0470143-0f342c73bfff4e1286a8a16301896cac

    (Code Snippet – Introduction to Windows Azure - Ex1 Create Queue – VB)

    Visual Basic

    Partial Public Class _Default
    FakePre-c151de55374f4a688fd329d0297ed899-5f0cac286f784a99af4edb6c78ede43eFakePre-f7715b9264d54d3f894e1818117ffd84-ec39c69f17a9438189be11a5ea8aa866FakePre-17b518bba96347e8ab895d573f0c4a75-44f3080ee4cc4bb2ad372ed66b4d5883FakePre-ebbb222132014efb851eaafd74bd8149-1466f7626a9a4919aa52cbc322031dbdFakePre-d13c3fcf8c864c6995ef46400036381f-018817bc932d4b7d9665d55714433756FakePre-54f2bd3b5fb3453a9d7532680d221a3c-3db00619d5df476ab6a4b70a39489e52FakePre-8c558ac002584fc3935096a196ad9230-4d86e4029ff44cfca2810327547ff2a6FakePre-78dac3e380ba41acb081cd693fb92c1b-b551f66a3ce94cd3910d926cf0236590FakePre-238e299b41e74bb6ac13b5ee86c9d76c-e046e7f7dd4f44dca68225cc09b4d582FakePre-0c485e1d7b4b4586b89169fccd097a3b-05bbf967df3e45308f6c942d53ccb343FakePre-29735a49199348d69843891ac5f91d44-a29a68dd2ce347919fd6d2c9ad5b677d ' create queue to communicate with worker role queueStorage = storageAccount.CreateCloudQueueClient() Dim queue As CloudQueue = queueStorage.GetQueueReference("guestthumbs") queue.CreateIfNotExist()FakePre-b980ea3599ea4ce59f2541b1928e3b2f-fe19235a8ff44c439334317a3850bacfFakePre-a74c281c44d249d29be6ae72b2974f97-11c1370aaa12444c8510db24ae104c1cFakePre-27816372cda64b198924be3c5ce86cdb-0c842c8b44f544d4bff6be56f8b588f1

    Note:
    The updated code creates a queue that the web role uses to submit new jobs to the worker role.

  4. Finally, add code to post a work item to the queue. To do this, locate the SignButton_Click event handler and insert the following (highlighted) code immediately after the lines that create a new entry in table storage.

    (Code Snippet – Introduction to Windows Azure - Ex1 Queueing work items – CS)

    C#

    protected void SignButton_Click(object sender, EventArgs e)
    FakePre-674a324946f341c1bd920da07a94feee-ca84ab1217d74b9794ac5db45da315e5FakePre-913d763b010142488d09ce7fcbc4b986-9edb16a64392420196297547ff07ce9eFakePre-0b585662fb1349759a16024d4fdebf27-7e6123cb2e0a4182aaa48728c5bfbc2eFakePre-b21e6af568234f8b9d3135812b25d9b1-f1b063c9508448d1bcd5e5f9418ef9f2FakePre-8d2364395eaf41f59a3bfae9b01562c5-2453510edff54e498e6b3a933a5e0d4bFakePre-0e8e7963f35e4e83a6c5fc895ed3fa9f-632296d9a96a4f79adc9a683582c35beFakePre-cf3ee02f66144376a0f4a41f9dacefba-12d78c694c6b499a9e60e675968d704cFakePre-55960f98388e405988617e9a27448aa6-09c469e0c2594807b4d38b184dba0f05FakePre-a31a9f64926f4ac9a81e116386996a66-143ee31449ab46b798529845ee9cbdabFakePre-f03b508211284f77ab6b22fc907285f1-a21b74025ead4c9cbb7968b9b327fb32FakePre-be3410f710b7489190ef3dd2f8c6c76d-2b97c8cc3a264d31a000e30ac27c4bf3 // queue a message to process the image var queue = queueStorage.GetQueueReference("guestthumbs"); var message = new CloudQueueMessage(String.Format("{0},{1},{2}", blob.Uri.ToString(), entry.PartitionKey, entry.RowKey)); queue.AddMessage(message); System.Diagnostics.Trace.TraceInformation("Queued message to process blob '{0}'", uniqueBlobName);FakePre-ef8bc911303849b1b7d7dfcd43c8b526-b994166c171b42aca6544267f1943d43FakePre-752135d1134c4404b9b465d1230bc3e3-15865a9b7a834fba95c62b7b6749d093FakePre-ba70f00676764e4c9916c924685a248c-c0657690bac940e28fb5c54ce4b0421eFakePre-744b8d19a8e54b77b1c4d36688121ec2-9950967dfcd847b9ab2102bdfce8ef9bFakePre-708377ddcee64cdfb93e12f812beb37c-2cbdfabb1ae14e458764f3d7b7233230FakePre-faf340dd88324eceaf11898fc37b41b4-9ed9eebf65f340c4bd096d5ccb924695FakePre-a3d054a1689a45c8a745c5186b7eff7f-5ea9dd88fc0e4f4c8f63772846929d2f

    (Code Snippet – Introduction to Windows Azure - Ex1 Queueing work items – VB)

    Visual Basic

    Protected Sub SignButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles SignButton.Click
    FakePre-d3a42a02e9c54201b4e690ee35885956-43cd87a6f9434ac981ddac898451a5deFakePre-9b0f6137add447568727cbcc8db6e7e8-b0a794aa62054797adecfc573f614901FakePre-390248f48f7b4687817bf5b4a11414a2-84ae0db45964411f828bb6a114dce018FakePre-df65b30718fe49d7bf26f550a115664d-4e75d663b2b8402982f16381adcb560dFakePre-c3692e4eddaa4218a269fac6400bde04-93b79801f67a45e8bf6bdaf99bf09618FakePre-6f5bde81dc7b4e6296f31f6be128b462-4e8a8a476bc443c39be4d00d59689513FakePre-f99779e528c94e6ba1b687dca57717a6-c410476d59c64bc58f7cf07d2b07b02fFakePre-d413c48b328a4047a3add908c56e7684-2d46465f4b2146c18b6c0a128b3032c7FakePre-6e34a4d4a9c44afd82d84a5091b4a92c-d67b403216bf414c985a18ee6a02072eFakePre-0345109f64c9435ca4a217aede52c0ad-2ba8eeec66594bbdbeb7352a0fad7f3e ' queue a message to process the image Dim queue = queueStorage.GetQueueReference("guestthumbs") Dim message = New CloudQueueMessage(String.Format("{0},{1},{2}", blob.Uri.ToString(), entry.PartitionKey, entry.RowKey)) queue.AddMessage(message) System.Diagnostics.Trace.TraceInformation("Queued message to process blob '{0}'", uniqueBlobName)FakePre-94b5f9df939b45be8bf7e069e2bba8f8-b018165ccb534401a58561c22840a6c9FakePre-dc93d9ff421a4e2ba781b27bc17bd801-74a0402ae6344628ac3bd30378bc8190FakePre-662a52fa65e44603a5d40c20421b1b78-6138d4341673436c9cc21e7e932b7233FakePre-86baa19bc1254cb5bbdfe949974a41df-7f6d56b844d04d119fc412abed8efeb5FakePre-1a2de3d06963494d843fa4aa3907f473-ba12bd4eff3f4a368576bb634640a69cFakePre-0831c57bc3204c0fbe944eb3338f9eb8-0614031802f14c86ab62ed30e44a7ec2FakePre-1594de98f4d94337a974166ba9235e54-983a10adfc0c454f82d01545ec4bea30

    Note:
    The updated code obtains a reference to the “guestthumbs” queue. It constructs a new message that consists of a comma-separated string with the name of the blob that contains the image, the partition key, and the row key of the entity that was added. The worker role can easily parse messages with this format. The method then submits the message to the queue.

Verification

The Windows Azure compute emulator, formerly Development Fabric or devfabric, is a simulated environment for developing and testing Windows Azure applications in your machine. In this task, you launch the GuestBook application in the emulator and create one or more guest book entries.

Among the features available in the Windows Azure Tools for Microsoft Visual Studio is a Windows Azure Storage browser that allows you to connect to a storage account and browse the blobs and tables it contains. If you are using this version of Visual Studio, you will use it during this task to examine the storage resources created by the application.

  1. Press F5 to execute the service. The service builds and then launches the local Windows Azure compute emulator. To show the Compute Emulator UI, right-click its icon located in the system tray and select Show Compute Emulator UI.

    Figure 14

    Showing the Compute Emulator UI

    Note:
    Note: If it is the first time you run the Windows Azure Emulator, the System will show a Windows Security Alert dialog indicating the Firewall has blocked some features. Click Allow Access to continue.

    Note:
    When you use the storage emulator for the first time, it needs to execute a one-time initialization procedure to create the necessary database and tables. If this is the case, wait for the procedure to complete and examine the Development Storage Initialization dialog to ensure that it completes successfully.

    Figure 15

    Storage emulator initialization process

  2. Switch to Internet Explorer to view the GuestBook application.
  3. Add a new entry to the guest book. To do this, type your name and a message, choose an image to upload from the Pictures\Sample Pictures library, and then click the pencil icon to submit the entry.

    Figure 16

    Windows Azure GuestBook home page

    Note:
    It is a good idea to choose a large hi-resolution image because, once the application is complete, the guestbook service will resize uploaded images.

    Once you submit an entry, the web role creates a new entity in the guest book table and uploads the photo to blob storage. The page contains a timer that triggers a page refresh every 5 seconds, so the new entry should appear on the page after a brief interval. Initially, the new entry contains a link to the blob that contains the uploaded image so it will appear with the same size as the original image.

    Figure 17

    GuestBook application showing an uploaded image in its original size

    If you are using Visual Studio 2010, you can use the Windows Azure Storage Explorer to view storage resources directly from Visual Studio. This functionality is not available in Visual Studio 2008.

  4. To open the Storage Explorer in Visual Studio 2010, open the View menu, select Server Explorer, and then expand the Windows Azure Storage node.

    The Windows Azure Storage node lists the storage accounts that you have currently registered and, by default, includes an entry for the storage emulator account labeled as (Development).

    Note:
    Windows Azure Storage Explorer is not available in Visual Studio 2008.

  5. Expand the (Development) node and then the Tables node inside it. Notice that it contains a table named GuestBookEntry created by the application that should contain details for each entry.

    Figure 18

    Viewing tables in the Windows Azure storage emulator

  6. Double-click the GuestBookEntry node in the Windows Azure Storage explorer to show the contents of this table. The GuestBookEntry table contains information for the entry that you created earlier in this task, including its GuestName, Message, PhotoUrl, and ThumbnailUrl properties, as well as the PartitionKey, RowKey, and Timestamp properties common to all table storage entities. Notice that the PhotoUrl and ThumbnailUrl properties are currently the same. In the next exercise, you will modify the application to generate image thumbnails and to update the corresponding URL.

    Figure 19

    Viewing tables using the Windows Azure Tools for Visual Studio

  7. Now, expand the Blobs node in the Windows Azure Storage explorer. Inside this node, you will find an entry for a container named guestbookpics that contains blobs with raw data for the images uploaded by the application.

    Figure 20

    Viewing blobs using the Windows Azure Tools for Visual Studio

  8. Double-click the node for the guestbookpics container to list the blobs it contains. It should include an entry for the image that you uploaded earlier.

    Figure 21

    Viewing the contents of a blob container in Visual Studio

  9. Each blob in blob storage has an associated content type that Visual Studio uses to select a suitable viewer for the blob. To display the contents of the blob, double-click the corresponding entry in the container listing to display the image.

    Figure 22

    Viewing blob contents in Visual Studio

  10. Press SHIFT + F5 to stop the debugger and shut down the deployment in the development fabric.