返回首页 Windows Azure入门教学系列

Windows Azure平台简介

Windows Azure入门教学系列

使用Windows Azure Drive

本文是 Windows Azure 入门教学 的第八篇文章。

本文将会介绍如何使用 Windows Azure Drive。

我们知道,由于云端的特殊性,通常情况下,对文件系统的读写建议使用 Blob Storage来代替。这就产生了一个问题:对于一个已经写好的本地应用程序,其中使用了 NTFS API对本地文件系统读写的代码是否需要进行完全重写以便迁移到 Windows Azure平台上呢?答案是否定的。 Windows Azure平台提供了 Drive的功能。

在 1.1版本的 SDK中提供了 CloudDrive类,能够将本地 NTFS文件系统 Mount到 Blob Storage上。我们只要添加一小段代码来表明我们希望 Mount Drive到 Blob Storage上就能重用大部分已有的对本地文件系统访问的代码。这样,我们已有的程序能够无缝地迁移到 Windows Azure上而不需要做大的改动。

在开始本教学之前,请确保你从Windows Azure 平台下载 下载并安装了最新的 Windows Azure开发工具。 本教学使用 Visual Studio 2010作为开发工具。

步骤一:创建解决方案和项目

由于我们要在本地模拟环境下测试 Windows Azure Drive,首先,请确保 Storage Emulator已经启动。我们可以找到管理器的进程手动启动或者让 Visual Studio 2010帮助我们启动他。

右击工具栏中 Windows Azure模拟器的图标,选择” Show Storage Emulator UI”。弹出如下图所示的窗口:

我们要关注的是 Service management中 Blob所在的一行。要确保 Status为 Running。

确认完毕后启动 Visual Studio 2010,新建一个 Cloud Service项目并为之添加一个 Web Role。

步骤二:添加 SDK 程序集引用

请在项目属性页里确认项目的 Target framework的值是 .NET Framework 4或 .NET Framework 3.5。然后在 Web Role项目中添加对 C:/Program Files/Windows Azure SDK/v1.3/ref/Microsoft.WindowsAzure.CloudDrive.dll的引用。该路径为 SDK默认安装路径,如果你不能在这个路径中找到 Microsoft.WindowsAzure.CloudDrive.dll请从 SDK安装路径中寻找。

步骤三:添加代码

删除并重新创建 Default.aspx 页面,然后在 Default.aspx.cs中引用命名空间:

using   Microsoft.WindowsAzure;

using   Microsoft.WindowsAzure.StorageClient;

using   System.IO;

然后添加下列代码:

public   partial   class   Default   : System.Web.UI.Page

{

     string   _driveLetter =  WebRole .DriveLetter;

     protected   void   Page_Load(object   sender,  EventArgs   e)

     {

         if   (!IsPostBack)

         {

             Bind();

         }

     }

     void   Bind()

     {

         //   显示被 Mount 的 Drive 根目录下的所有文件

         DirectoryInfo   di =  new   DirectoryInfo (string .Format("{0}//" , _driveLetter));

         this .GridView1.DataSource = di.GetFiles();

         this .GridView1.DataBind();

     }

     protected   void   Button1_Click(object   sender,  EventArgs   e)

     {

         //   在被 Mount 的 Drive 根目录下保存文件

         if   (this .FileUpload1.HasFile)

         {

             File .WriteAllBytes(string .Format("{0}//{1}" , _driveLetter,  this .FileUpload1.FileName),  this .FileUpload1.FileBytes);

             Bind();

         }

     }

}

在 Default.aspx中添加下列代码:

< form   id ="form1"   runat ="server">

     < asp : FileUpload   ID ="FileUpload1"   runat ="server"   />

     < asp : Button   ID ="Button1"   runat ="server"   Text ="Upload"   onclick ="Button1_Click"   />

     < asp : GridView   AllowPaging ="true"   PageSize ="20"   ID ="GridView1"   runat ="server">

     </ asp : GridView >

</ form >

接下来在 WebRole.cs中引用命名空间:

using   Microsoft.WindowsAzure.StorageClient;

然后添加下列代码:

public   class   WebRole   :  RoleEntryPoint

{

     public   static   string   DriveLetter {  get ;  private   set ; }

     CloudDrive   myCloudDrive;

     public   override   bool   OnStart()

     {

         //   当用配置文件中 ConfigurationSettings 时必须调用 CloudStorageAccount.SetConfigurationSettingPublisher

         //  来说明当配置文件在发布后被更改时将采取何种操作

         CloudStorageAccount .SetConfigurationSettingPublisher((configName, configSetter) =>

         {

             configSetter(RoleEnvironment .GetConfigurationSettingValue(configName));

             RoleEnvironment .Changed += (sender, arg) =>

             {

                 if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange >()

                     .Any((change) => (change.ConfigurationSettingName == configName)))

                 {

                     if (!configSetter(RoleEnvironment .GetConfigurationSettingValue(configName)))

                     {

                         RoleEnvironment .RequestRecycle();

                      }

                 }

             };

         });

         // For information on handling configuration changes

         // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

         return   base .OnStart();

     }

     public   override   void     Run()

     {

         CloudStorageAccount   storageAccount =  CloudStorageAccount .FromConfigurationSetting("DataConnectionString" );

         LocalResource   localCache =  RoleEnvironment .GetLocalResource("InstanceDriveCache" );

         CloudDrive .InitializeCache(localCache.RootPath, localCache.MaximumSizeInMegabytes);

         //   检查 Container 是否存在,不存在则创建

         CloudBlobClient   blobClient = storageAccount.CreateCloudBlobClient();

         blobClient.GetContainerReference("drives" ).CreateIfNotExist();

         //   创建 Cloud Drive

         myCloudDrive = storageAccount.CreateCloudDrive(

             blobClient

             .GetContainerReference("drives" )

             .GetPageBlobReference("mydrive.vhd" )

             .Uri.ToString()

         );

         try

         {

              myCloudDrive.Create(64);

         }

         catch   (CloudDriveException )

         {

         }

         DriveLetter = myCloudDrive.Mount(0,  DriveMountOptions .Force);

           base .Run();

     }

     public   override   void   OnStop()

     {

         myCloudDrive.Unmount();

         base .OnStop();

     }

}

最后,修改配置文件。在 Cloud Service项目的 ServiceConfiguration.cscfg中添加下列配置:

<? xml   version = "1.0 "  encoding = "utf-8 "?>

< ServiceConfiguration   serviceName = "WindowsAzureDriveDemonstration "xmlns = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration "  osFamily = "1 "  osVersion = "* ">

   < Role   name = "WebRole1 ">

     < Instances   count = "1 "  />

     < ConfigurationSettings >

       < Setting   name = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString "  value = "UseDevelopmentStorage=true "  />

       < Setting   name = "DataConnectionString "  value = "UseDevelopmentStorage=true "  />

     </ ConfigurationSettings >

   </ Role >

</ ServiceConfiguration >

在 ServiceDefinition.csdef中添加下列配置(注意将 Sites部分的内容删除或注释掉):

<? xml   version = "1.0 "  encoding = "utf-8 "?>

< ServiceDefinition   name = "WindowsAzureDriveDemonstration "  xmlns = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition ">

   < WebRole   name = "WebRole1 ">

     < Sites >

       < Site   name = "Web ">

         < Bindings >

           < Binding   name = "Endpoint1 "  endpointName = "Endpoint1 "  />

         </ Bindings >

       </ Site >

     </ Sites >

     < Endpoints >

       < InputEndpoint   name = "Endpoint1 "  protocol = "http "  port = "80 "  />

     </ Endpoints >

     < Imports >

       < Import   moduleName = "Diagnostics "  />

     </ Imports >

     < LocalResources >

         < LocalStorage   name = "InstanceDriveCache "  cleanOnRoleRecycle = "false "  sizeInMB = "300 "  />

     </ LocalResources >

     < ConfigurationSettings >

         < Setting   name = "DataConnectionString "  />

     </ ConfigurationSettings >

   </ WebRole >

</ ServiceDefinition >

步骤四:观察并分析代码

步骤三中的代码中, Default.aspx.cs的代码跟普通的 ASP.NET项目代码没什么区别。我们把盘符抽离出来以便迁移到 Windows Azure上。 Default.aspx.cs中的代码跟 Windows Azure唯一相关的一句语句就是 string driveLetter = WebRole .DriveLetter 。 我们如果把 WebRole .DriveLetter 替换为本机盘符该 ASP.NET程序将能够正常运行。

后面的代码示范了如何 Mount Drive到 Blob Storage。此外我们使用了本地缓存来缓存尚未被传递到 Blob Storage的文件。

通过上面的例子可以看到,只需额外添加一小段代码,已有的使用 NTFS API的程序能够很方便地迁移到 Windows Azure平台上。

步骤五:运行程序

运行程序。上传几个文件。如果一切顺利你将看到下图所示的结果。可以看到文件的 DirectoryName为“ a:/”。这就是被 Mount到 Blob Storage上的 Drive的盘符。

需要注意的是,本例中我们并未修改 WebRole的实例数,因此只有 1个 WebRole(发布到云端后将只有一个虚拟机被使用)。如果有两个实例,并且要让两个实例共享一个”网络硬盘“的话,本例中代码将不能正常工作。因为对于同一个 Blob同时只能有一个虚拟机 Mount。一个可能的解决方案是额外维护一个 Web Service来管理 Mount和 UnMount Drive。进一步的讨论超出了本教学的范围。有兴趣的读者可以下载并参考 Windows Azure Cloud Drive白皮书 获取信息。