Building Windows Azure Service Part4: Web Role UI Handler
In this post, you will create the UI that enables the user to perform read, write operations on the GuestBookEntry table. You will update the web role project generated when you created the Windows Azure service. Specifically, you will perform the following tasks:
- Add a page to the project that contains the UI to display the guest GuestBookEntry table.
- Create the code that enables the user to store guest information in Table Storage and images in Blob Storage.
- Finally, configure the storage account used by the web role.
Happy Holidays
To render the guest book
- In Solution Explorer right-click the GuestBook_WebRole project, select Add Reference.
- Add a reference to the Microsoft.WindowsAzure.StorageClient assembly.
- Add a reference to the GuestBookData project.
- Open the default.aspx file.
- Replace the file content with the following markup.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="GuestBook_WebRole._Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="https://www.w3.org/1999/xhtml"> <head id="Head1" runat="server"> <title>Windows Azure Guestbook</title> <link href="main.css" rel="stylesheet" type="text/css" /> </head> <body> <form id="form1" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <div class="general"> <div class="title"> <h1> Windows Azure GuestBook </h1> </div> <div class="inputSection"> <dl> <dt> <label for="NameLabel">Name:</label></dt> <dd> <asp:TextBox ID="NameTextBox" runat="server" CssClass="field"/> <asp:RequiredFieldValidator ID="NameRequiredValidator" runat="server" ControlToValidate="NameTextBox" Text="*" /> </dd> <dt> <label for="MessageLabel">Message:</label> </dt> <dd> <asp:TextBox ID="MessageTextBox" runat="server" TextMode="MultiLine" CssClass="field" /> <asp:RequiredFieldValidator ID="MessageRequiredValidator" runat="server" ControlToValidate="MessageTextBox" Text="*" /> </dd> <dt> <label for="FileUpload1">Photo:</label></dt> <dd> <asp:FileUpload ID="FileUpload1" runat="server" size="16" /> <asp:RequiredFieldValidator ID="PhotoRequiredValidator" runat="server" ControlToValidate="FileUpload1" Text="*" /> <asp:RegularExpressionValidator ID="PhotoRegularExpressionValidator" runat="server" ControlToValidate="FileUpload1" ErrorMessage="Only .jpg or .png files are allowed" ValidationExpression="([a-zA-Z\\].*(.jpg|.JPG|.png|.PNG)$)" /> </dd> </dl> <div class="inputSignSection"> <asp:ImageButton ID="SignButton" runat="server" AlternateText="Sign GuestBook" onclick="SignButton_Click" ImageUrl="~/sign.png" ImageAlign="Bottom" /> </div> </div> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <asp:DataList ID="DataList1" runat="server" DataSourceID="ObjectDataSource1"> <ItemTemplate> <div class="signature"> <div class="signatureImage"> <a href="<%# Eval("PhotoUrl") %>" target="_blank"> <img src="<%# Eval("ThumbnailUrl") %>" alt="<%# Eval("GuestName") %>" /> </a> </div> <div class="signatureDescription"> <div class="signatureName"> <%# Eval("GuestName") %> </div> <div class="signatureSays"> says </div> <div class="signatureDate"> <%#((DateTime)Eval("Timestamp")).ToShortDateString() %> </div> <div class="signatureMessage"> "<%# Eval("Message") %>" </div> </div> </div> </ItemTemplate> </asp:DataList> <asp:Timer ID="Timer1" runat="server" Interval="15000" OnTick="Timer1_Tick"> </asp:Timer> </ContentTemplate> </asp:UpdatePanel> <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DataObjectTypeName="GuestBook_Data.GuestBookEntry" InsertMethod="AddGuestBookEntry" SelectMethod="Select" TypeName="GuestBook_Data.GuestBookEntryDataSource"> </asp:ObjectDataSource> </div> </form> </body>
</html>
To store guest information in Table and Blob Storage
To allow the user to enter guest information and store the entry in Table Storage and the related image in the Blob Storage, you must execute the following steps.
- In Solution Explorer open the default.aspx.cs file.
- Replace the file content with the following code.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Net; using GuestBook_Data; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime; using Microsoft.WindowsAzure.StorageClient; using System.Text; namespace GuestBook_WebRole { public partial class _Default : System.Web.UI.Page { private static bool storageInitialized = false; private static object gate = new Object(); private static CloudBlobClient blobStorage; private static CloudQueueClient queueStorage; protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { Timer1.Enabled = true; } } protected void SignButton_Click(object sender, EventArgs e) { if (FileUpload1.HasFile) { InitializeStorage(); // upload the image to blob storage CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics"); string uniqueBlobName = string.Format("image_{0}.jpg",
Guid.NewGuid().ToString()); CloudBlockBlob blob = container.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() }; GuestBookEntryDataSource ds = new GuestBookEntryDataSource(); ds.AddGuestBookEntry(entry); System.Diagnostics.Trace.TraceInformation( "Added entry {0}-{1} in table storage for guest '{2}'", entry.PartitionKey, entry.RowKey, entry.GuestName); // queue a message to process the image var queue = queueStorage.GetQueueReference("guestthumbs"); var message = new CloudQueueMessage(String.Format("{0},{1},{2}", uniqueBlobName, entry.PartitionKey, entry.RowKey)); queue.AddMessage(message); System.Diagnostics.Trace.TraceInformation( "Queued message to process blob '{0}'", uniqueBlobName); } NameTextBox.Text = ""; MessageTextBox.Text = ""; DataList1.DataBind(); } protected void Timer1_Tick(object sender, EventArgs e) { DataList1.DataBind(); } private void InitializeStorage() { if (storageInitialized) { return; } lock (gate) { if (storageInitialized) { return; } try { // Create a new instance of a CloudStorageAccount object from a specified configuration setting. // This method may be called only after the SetConfigurationSettingPublisher // method has been called to configure the global configuration setting publisher. // You can call the SetConfigurationSettingPublisher method in the OnStart method // of the web role or in the Application_Start method in the Global.asax.cs file. // If you do not do this, the system raises an exception 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); // create queue to communicate with worker role queueStorage = storageAccount.CreateCloudQueueClient(); CloudQueue queue = queueStorage.GetQueueReference("guestthumbs"); queue.CreateIfNotExist(); } catch (WebException) { StringBuilder buffer = new StringBuilder(); buffer.Append("Storage services initialization failure."); buffer.Append(" Check your storage account configuration settings."); buffer.Append(" If running locally,"); buffer.Append(" ensure that the Development Storage service is running."); throw new WebException(buffer.ToString()); } storageInitialized = true; } } } }
To configure the storage account for the web role
In order for the web role to use the Windows Azure storage services, you must provide account settings as shown next.
- In Solution Explorer, expand the Role node in the GuestBook project.
- Double click GuestBook_WebRole to open the properties for this role and select Settings tab.
- Click Add Settings.
- In the Name column, enter DataConnectionString.
- 12. In the Type column from the drop-down list select ConnectionString.
- 13. In the Value column, from the drop-down list, select Use development storage.
- 14. Click OK. Then press Ctrl+S to save your changes.
Figure 6 Configuring Storage Account For Web Role
A storage account is a unique end- point for Windows Azure blob, queue and table services. You must create a storage account to use these services. For more information, see Windows Azure Platform.
This walkthrough uses the development storage included in the Windows Azure SDK development environment to simulate blob, queue, and table services available in the cloud. Windows Azure by default uses SQL Server Express to simulate these services. You can also use a local instance of the SQL Server. To do so you must define the connection string that the development storage can use to connect to the server. For more information, see Using Windows Azure Development Environment Essentials.
To use the development storage, you set the value of the UseDevelopmentStorage keyword in the connection string for the storage account to true. When you deploy 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" /> |
For related topics, see the following posts.
- Building Windows Azure Service Part1: Introduction
- Building Windows Azure Service Part2: Service Project.
- Building Windows Azure Service Part3: Table Storage
- Building Windows Azure Service Part5: Worker Role Background Tasks Handler
- Building Windows Azure Service Part6: Service Configuration
- Building Windows Azure Service Part7: Service Testing
Comments
- Anonymous
January 17, 2011
Question, where is the .css file coming from? I don't see a download or anything.