Building Your First Windows Azure Application

Training Kits里的第一篇实例教程,简单记录下过程,并根据理解做些旁注,方便日后查看。

 image

 

1. 新建一个Cloud Service工程, 增加一个ASP.NET Web Role

image

 

2. 增加一个Class Library, 添加所需References,定义Entity Schema -- GuestBookEntry.cs

GuestBookEntry.cs
  1. using System;
  2. using Microsoft.WindowsAzure.StorageClient;
  3.  
  4. namespace GuestBook_Data
  5. {
  6.     public class GuestBookEntry : TableServiceEntity
  7.     {
  8.         public GuestBookEntry()
  9.         {
  10.             PartitionKey = DateTime.UtcNow.ToString("MMddyyyy");
  11.  
  12.             // Row key allows sorting, so we make sure the rows come back in time order.
  13.             RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
  14.         }
  15.  
  16.         public string Message { get; set; }
  17.         public string GuestName { get; set; }
  18.         public string PhotoUrl { get; set; }
  19.         public string ThumbnailUrl { get; set; }
  20.     }
  21. }

注:

    定义的 Entity 存于 Windows Azure table 中,故继承自 TableServiceEntity。 

    TableServiceEntity 类中定义了PartititionKey, RowKey 和 TimeStamp,该3个字段是存在Windows Azure table 中必要的字段,其中 PartitionKey 和 RowKey 都是string类型,合起来可以确定一个 DataServiceKey, 进而可以唯一确定 Table 中的一个 Entity。

    该例在 Entity 构造函数中对 PartititionKey, RowKey 赋值,以便在新建立一个 Entity 时无须显式的为这两个字段赋值。其中用日期作为PartititionKey的值,这样对于每一天建立的Entities都会有一个Partition, 一般来讲, PartititionKey的选值需要考虑到节点间的负载平衡问题。 RowKey用反序的时间加一个guid来确定,加guid为了保证唯一性,时间反转则是考虑到排序问题,总是让最新的entities排在前面。

 

3. 定义DataContext -- GuestBookDataContext.cs

GuestBookDataContext.cs
  1. using System.Linq;
  2.  
  3. using Microsoft.WindowsAzure;
  4. using Microsoft.WindowsAzure.StorageClient;
  5.  
  6. namespace GuestBook_Data
  7. {
  8.     public class GuestBookDataContext : TableServiceContext
  9.     {
  10.         public GuestBookDataContext(string baseAddress, StorageCredentials credentials)
  11.             : base(baseAddress, credentials)
  12.         {
  13.         }
  14.  
  15.         public IQueryable<GuestBookEntry> GuestBookEntry
  16.         {
  17.             get
  18.             {
  19.                 return this.CreateQuery<GuestBookEntry>("GuestBookEntry");
  20.             }
  21.         }
  22.     }
  23. }

注:

    同样对应于table的DataContext需要继承于 TableServiceContext 类。 其中构造函数中StorageCredentials参数存储通过storage account访问Windows Azure storage service需要的验证信息等。

 

4. 定义GuestBookEntryDataSource.cs

GuestBookEntryDataSource.cs
  1. using System;
  2. using System.Linq;
  3. using System.Collections.Generic;
  4.  
  5. using Microsoft.WindowsAzure;
  6. using Microsoft.WindowsAzure.StorageClient;
  7.  
  8. namespace GuestBook_Data
  9. {
  10.     public class GuestBookEntryDataSource
  11.     {
  12.         private static CloudStorageAccount storageAccount;
  13.         private GuestBookDataContext context;
  14.         
  15.         public GuestBookEntryDataSource()
  16.         {
  17.             this.context = new GuestBookDataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
  18.             this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
  19.         }
  20.  
  21.         static GuestBookEntryDataSource()
  22.         {
  23.             storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
  24.  
  25.             CloudTableClient.CreateTablesFromModel(
  26.                 typeof(GuestBookDataContext), storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
  27.         }
  28.  
  29.         public IEnumerable<GuestBookEntry> Select()
  30.         {
  31.             var results = from g in this.context.GuestBookEntry
  32.                           where g.PartitionKey == DateTime.UtcNow.ToString("MMddyyyy")
  33.                           select g;
  34.             return results;
  35.         }
  36.  
  37.         public void AddGuestBookEntry(GuestBookEntry newItem)
  38.         {
  39.             this.context.AddObject("GuestBookEntry", newItem);
  40.             this.context.SaveChanges();
  41.         }
  42.  
  43.         public void UpdateImageThumbnail(string partitionKey, string rowKey, string thumbUrl)
  44.         {
  45.             var results = from g in this.context.GuestBookEntry
  46.                           where g.PartitionKey == partitionKey && g.RowKey == rowKey
  47.                           select g;
  48.  
  49.             var entry = results.FirstOrDefault<GuestBookEntry>();
  50.             entry.ThumbnailUrl = thumbUrl;
  51.             this.context.UpdateObject(entry);
  52.             this.context.SaveChanges();
  53.         }
  54.     }
  55. }

 

注:

静态构造函数中 storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString"); 配置信息存储在GuestBook_WebRole中,见下图:

image

 

5. 利用 Web Role 来完成UI部分. UI 部分的 code 如下

Default.aspx.cs
  1.  
  2. using System;
  3. using System.Web.UI;
  4.  
  5. using System.Net;
  6. using GuestBook_Data;
  7. using Microsoft.WindowsAzure;
  8. using Microsoft.WindowsAzure.StorageClient;
  9.  
  10. namespace GuestBook_WebRole
  11. {
  12.     public partial class _Default : System.Web.UI.Page
  13.     {
  14.         private static bool storageInitialized = false;
  15.         private static object gate = new Object();
  16.         private static CloudBlobClient blobStorage;
  17.         private static CloudQueueClient queueStorage;
  18.  
  19.         protected void Page_Load(object sender, EventArgs e)
  20.         {
  21.             if (!Page.IsPostBack)
  22.             {
  23.                 Timer1.Enabled = true;
  24.             }
  25.         }
  26.  
  27.         protected void SignButton_Click(object sender, EventArgs e)
  28.         {
  29.             if (FileUpload1.HasFile)
  30.             {
  31.                 InitializeStorage();
  32.  
  33.                 // upload the image to blob storage
  34.                 string uniqueBlobName = string.Format("image_{0}.jpg", Guid.NewGuid().ToString());
  35.  
  36.                 CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics");
  37.                 CloudBlockBlob blob = container.GetBlockBlobReference(uniqueBlobName);
  38.                 blob.Properties.ContentType = FileUpload1.PostedFile.ContentType;
  39.                 blob.UploadFromStream(FileUpload1.FileContent);
  40.                 System.Diagnostics.Trace.TraceInformation(
  41.                     "Uploaded image '{0}' to blob storage as '{1}'", FileUpload1.FileName, uniqueBlobName);
  42.  
  43.                 // create a new entry in table storage
  44.                 GuestBookEntry entry = new GuestBookEntry() {
  45.                     GuestName = NameTextBox.Text,
  46.                     Message = MessageTextBox.Text,
  47.                     PhotoUrl = blob.Uri.ToString(),
  48.                     ThumbnailUrl = blob.Uri.ToString() };
  49.  
  50.                 GuestBookEntryDataSource ds = new GuestBookEntryDataSource();
  51.                 ds.AddGuestBookEntry(entry);
  52.                 System.Diagnostics.Trace.TraceInformation(
  53.                     "Added entry {0}-{1} in table storage for guest '{2}'",
  54.                     entry.PartitionKey, entry.RowKey, entry.GuestName);
  55.  
  56.                 // queue a message to process the image
  57.                 var queue = queueStorage.GetQueueReference("guestthumbs");
  58.                 var message = new CloudQueueMessage(String.Format("{0},{1},{2}", uniqueBlobName, entry.PartitionKey, entry.RowKey));
  59.                 queue.AddMessage(message);
  60.                 System.Diagnostics.Trace.TraceInformation("Queued message to process blob '{0}'", uniqueBlobName);
  61.             }
  62.  
  63.             NameTextBox.Text = "";
  64.             MessageTextBox.Text = "";
  65.  
  66.             DataList1.DataBind();
  67.         }
  68.  
  69.         protected void Timer1_Tick(object sender, EventArgs e)
  70.         {
  71.             DataList1.DataBind();
  72.         }
  73.  
  74.         private void InitializeStorage()
  75.         {
  76.             if (storageInitialized)
  77.             {
  78.                 return;
  79.             }
  80.  
  81.             lock (gate)
  82.             {
  83.                 if (storageInitialized)
  84.                 {
  85.                     return;
  86.                 }
  87.  
  88.                 try
  89.                 {
  90.                     // read account configuration settings
  91.                     var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
  92.  
  93.                     // create blob container for images
  94.                     blobStorage = storageAccount.CreateCloudBlobClient();
  95.                     CloudBlobContainer container = blobStorage.GetContainerReference("guestbookpics");
  96.                     container.CreateIfNotExist();
  97.  
  98.                     // configure container for public access
  99.                     var permissions = container.GetPermissions();
  100.                     permissions.PublicAccess = BlobContainerPublicAccessType.Container;
  101.                     container.SetPermissions(permissions);
  102.  
  103.                     // create queue to communicate with worker role
  104.                     queueStorage = storageAccount.CreateCloudQueueClient();
  105.                     CloudQueue queue = queueStorage.GetQueueReference("guestthumbs");
  106.                     queue.CreateIfNotExist();
  107.                 }
  108.                 catch (WebException)
  109.                 {
  110.                     throw new WebException("Storage services initialization failure. "
  111.                         + "Check your storage account configuration settings. If running locally, "
  112.                         + "ensure that the Development Storage service is running.");
  113.                 }
  114.  
  115.                 storageInitialized = true;
  116.             }
  117.         }
  118.     }
  119. }
 

注:

InitializeStorage方法建立了一个blob container用来存储图片,并且设置相应权限。

点击Sign button时,将Image信息存储于blob storage, 将GuestBook Entity信息存储于table storage。

 

6. 增加一个storage account settings, 双击GuestBook_WebRole,Add Settings

image

image

 

7. 修改WebRole.cs的 OnStart() 方法

WebRole.cs
  1. using System.Linq;
  2. using Microsoft.WindowsAzure.Diagnostics;
  3. using Microsoft.WindowsAzure.ServiceRuntime;
  4. using Microsoft.WindowsAzure;
  5.  
  6. namespace GuestBook_WebRole
  7. {
  8.     public class WebRole : RoleEntryPoint
  9.     {
  10.         public override bool OnStart()
  11.         {
  12.             DiagnosticMonitor.Start("DiagnosticsConnectionString");
  13.  
  14.             // For information on handling configuration changes
  15.             // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
  16.             RoleEnvironment.Changing += RoleEnvironmentChanging;
  17.  
  18.             CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
  19.             {
  20.                 configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
  21.             });
  22.  
  23.             return base.OnStart();
  24.         }
  25.  
  26.         private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
  27.         {
  28.             // If a configuration setting is changing
  29.             if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
  30.             {
  31.                 // Set e.Cancel to true to restart this role instance
  32.                 e.Cancel = true;
  33.             }
  34.         }
  35.     }
  36. }

 

8. 新建一个Worker Role

image 

WorkerRole.cs
  1. using System;
  2. using System.Diagnostics;
  3. using System.Linq;
  4. using System.Net;
  5. using Microsoft.WindowsAzure.Diagnostics;
  6. using Microsoft.WindowsAzure.ServiceRuntime;
  7.  
  8. using System.Drawing;
  9. using System.IO;
  10. using GuestBook_Data;
  11. using Microsoft.WindowsAzure;
  12. using Microsoft.WindowsAzure.StorageClient;
  13.  
  14. namespace GuestBook_WorkerRole
  15. {
  16.     public class WorkerRole : RoleEntryPoint
  17.     {
  18.         private CloudQueue queue;
  19.         private CloudBlobContainer container;
  20.  
  21.         public override void Run()
  22.         {
  23.             Trace.TraceInformation("Listening for queue messages...");
  24.  
  25.             while (true)
  26.             {
  27.                 try
  28.                 {
  29.                     // retrieve a new message from the queue
  30.                     CloudQueueMessage msg = queue.GetMessage();
  31.                     if (msg != null)
  32.                     {
  33.                         // parse message retrieved from queue
  34.                         var messageParts = msg.AsString.Split(new char[] { ',' });
  35.                         var uri = messageParts[0];
  36.                         var partitionKey = messageParts[1];
  37.                         var rowkey = messageParts[2];
  38.                         Trace.TraceInformation("Processing image in blob '{0}'.", uri);
  39.  
  40.                         // download original image from blob storage
  41.                         CloudBlockBlob imageBlob = container.GetBlockBlobReference(uri);
  42.                         MemoryStream image = new MemoryStream();
  43.                         imageBlob.DownloadToStream(image);
  44.                         image.Seek(0, SeekOrigin.Begin);
  45.  
  46.                         // create a thumbnail image and upload into a blob
  47.                         string thumbnailUri = String.Concat(Path.GetFileNameWithoutExtension(uri), "_thumb.jpg");
  48.                         CloudBlockBlob thumbnailBlob = container.GetBlockBlobReference(thumbnailUri);
  49.                         thumbnailBlob.UploadFromStream(CreateThumbnail(image));
  50.  
  51.                         // update the entry in table storage to point to the thumbnail
  52.                         var ds = new GuestBookEntryDataSource();
  53.                         ds.UpdateImageThumbnail(partitionKey, rowkey, thumbnailBlob.Uri.AbsoluteUri);
  54.  
  55.                         // remove message from queue
  56.                         queue.DeleteMessage(msg);
  57.  
  58.                         Trace.TraceInformation("Generated thumbnail in blob '{0}'.", thumbnailBlob.Uri);
  59.                     }
  60.                     else
  61.                     {
  62.                         System.Threading.Thread.Sleep(1000);
  63.                     }
  64.                 }
  65.                 catch (StorageClientException e)
  66.                 {
  67.                     Trace.TraceError("Exception when processing queue item. Message: '{0}'", e.Message);
  68.                     System.Threading.Thread.Sleep(5000);
  69.                 }
  70.             }
  71.         }
  72.  
  73.         public override bool OnStart()
  74.         {
  75.             // Set the maximum number of concurrent connections
  76.             ServicePointManager.DefaultConnectionLimit = 12;
  77.  
  78.             DiagnosticMonitor.Start("DiagnosticsConnectionString");
  79.  
  80.             // For information on handling configuration changes
  81.             // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
  82.             RoleEnvironment.Changing += RoleEnvironmentChanging;
  83.             
  84.             // read storage account configuration settings
  85.             CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
  86.             {
  87.                 configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
  88.             });
  89.  
  90.             var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
  91.  
  92.             // initialize blob storage
  93.             CloudBlobClient blobStorage = storageAccount.CreateCloudBlobClient();
  94.             container = blobStorage.GetContainerReference("guestbookpics");
  95.  
  96.             // initialize queue storage
  97.             CloudQueueClient queueStorage = storageAccount.CreateCloudQueueClient();
  98.             queue = queueStorage.GetQueueReference("guestthumbs");
  99.  
  100.             Trace.TraceInformation("Creating container and queue...");
  101.  
  102.             bool storageInitialized = false;
  103.             while (!storageInitialized)
  104.             {
  105.                 try
  106.                 {
  107.                     // create the blob container and allow public access
  108.                     container.CreateIfNotExist();
  109.                     var permissions = container.GetPermissions();
  110.                     permissions.PublicAccess = BlobContainerPublicAccessType.Container;
  111.                     container.SetPermissions(permissions);
  112.  
  113.                     // create the message queue
  114.                     queue.CreateIfNotExist();
  115.                     storageInitialized = true;
  116.                 }
  117.                 catch (StorageClientException e)
  118.                 {
  119.                     if (e.ErrorCode == StorageErrorCode.TransportError)
  120.                     {
  121.                         Trace.TraceError("Storage services initialization failure. "
  122.                           + "Check your storage account configuration settings. If running locally, "
  123.                           + "ensure that the Development Storage service is running. Message: '{0}'", e.Message);
  124.                         System.Threading.Thread.Sleep(5000);
  125.                     }
  126.                     else
  127.                     {
  128.                         throw;
  129.                     }
  130.                 }
  131.             }
  132.  
  133.             return base.OnStart();
  134.         }
  135.  
  136.         private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
  137.         {
  138.             // If a configuration setting is changing
  139.             if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
  140.             {
  141.                 // Set e.Cancel to true to restart this role instance
  142.                 e.Cancel = true;
  143.             }
  144.         }
  145.  
  146.         private Stream CreateThumbnail(Stream input)
  147.         {
  148.             var orig = new Bitmap(input);
  149.             int width;
  150.             int height;
  151.             if (orig.Width > orig.Height)
  152.             {
  153.                 width = 128;
  154.                 height = 128 * orig.Height / orig.Width;
  155.             }
  156.             else
  157.             {
  158.                 height = 128;
  159.                 width = 128 * orig.Width / orig.Height;
  160.             }
  161.             var thumb = new Bitmap(width, height);
  162.             using (Graphics graphic = Graphics.FromImage(thumb))
  163.             {
  164.                 graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
  165.                 graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
  166.                 graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
  167.                 graphic.DrawImage(orig, 0, 0, width, height);
  168.                 var ms = new MemoryStream();
  169.                 thumb.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
  170.                 ms.Seek(0, SeekOrigin.Begin);
  171.                 return ms;
  172.             }
  173.         }
  174.     }
  175. }

 

注:

至此,该程序应该可以运行了,完成的功能就是用户通过页面上传GuestBook信息,其中Image存储于blob storage中,GuestBook Entity存储于table storage中, web role和worker role之间通过queue storage进行消息的传递,用户发的消息以一定格式存储于queue storage中, 在worker role中以一定频率去读取queue storage中的信息并进行相应处理。

posted @ 2009-12-24 15:18  咋攒都五块  阅读(579)  评论(0编辑  收藏  举报