我們知道,由于雲端的特殊性,通常情況下,對檔案系統的讀寫建議使用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 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 FilesWindows Azure SDKv1.3refMicrosoft.WindowsAzure.CloudDrive.dll的引用。該路徑為SDK預設安裝路徑,如果你不能在這個路徑中找到Microsoft.WindowsAzure.CloudDrive.dll請從SDK安裝路徑中尋找。
步驟三:添加代碼
删除并重新建立Default.aspx 頁面,然後在Default.aspx.cs中引用命名空間:
1
2
3
4
5
<code>using Microsoft.WindowsAzure;</code>
<code>using Microsoft.WindowsAzure.StorageClient;</code>
<code>using System.IO;</code>
然後添加下列代碼:
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<code>public partial class Default : System.Web.UI.Page</code>
<code>{</code>
<code> </code><code>string _driveLetter = WebRole.DriveLetter;</code>
<code> </code>
<code> </code><code>protected void Page_Load(object sender, EventArgs e)</code>
<code> </code><code>{</code>
<code> </code><code>if (!IsPostBack)</code>
<code> </code><code>{</code>
<code> </code><code>Bind();</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>void Bind()</code>
<code> </code><code>// 顯示被Mount的Drive根目錄下的所有檔案</code>
<code> </code><code>DirectoryInfo di = new DirectoryInfo(string.Format("{0}", _driveLetter));</code>
<code> </code><code>this.GridView1.DataSource = di.GetFiles();</code>
<code> </code><code>this.GridView1.DataBind();</code>
<code> </code><code>protected void Button1_Click(object sender, EventArgs e)</code>
<code> </code><code>// 在被Mount的Drive根目錄下儲存檔案</code>
<code> </code><code>if (this.FileUpload1.HasFile)</code>
<code> </code><code>File.WriteAllBytes(string.Format("{0}{1}", _driveLetter, this.FileUpload1.FileName), this.FileUpload1.FileBytes);</code>
<code>}</code>
在Default.aspx中添加下列代碼:
<code><</code><code>form</code> <code>id</code><code>=</code><code>"form1"</code> <code>runat</code><code>=</code><code>"server"</code><code>></code>
<code> </code><code><</code><code>asp:FileUpload</code> <code>ID</code><code>=</code><code>"FileUpload1"</code> <code>runat</code><code>=</code><code>"server"</code> <code>/></code>
<code> </code><code><</code><code>asp:Button</code> <code>ID</code><code>=</code><code>"Button1"</code> <code>runat</code><code>=</code><code>"server"</code> <code>Text</code><code>=</code><code>"Upload"</code> <code>onclick</code><code>=</code><code>"Button1_Click"</code> <code>/></code>
<code> </code><code><</code><code>asp:GridView</code> <code>AllowPaging</code><code>=</code><code>"true"</code> <code>PageSize</code><code>=</code><code>"20"</code> <code>ID</code><code>=</code><code>"GridView1"</code> <code>runat</code><code>=</code><code>"server"</code><code>></code>
<code> </code><code></</code><code>asp:GridView</code><code>></code>
<code></</code><code>form</code><code>></code>
接下來在WebRole.cs中引用命名空間:
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<code>public class WebRole : RoleEntryPoint</code>
<code> </code><code>public static string DriveLetter { get; private set; }</code>
<code> </code><code>CloudDrive myCloudDrive;</code>
<code> </code><code>public override bool OnStart()</code>
<code> </code><code>// 當用配置檔案中ConfigurationSettings時必須調用CloudStorageAccount.SetConfigurationSettingPublisher</code>
<code> </code><code>// 來說明當配置檔案在釋出後被更改時将采取何種操作</code>
<code> </code><code>CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =></code>
<code> </code>
<code> </code><code>configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));</code>
<code> </code><code>RoleEnvironment.Changed += (sender, arg) =></code>
<code> </code><code>{</code>
<code> </code><code>if(arg.Changes.OfType<</code><code>RoleEnvironmentConfigurationSettingChange</code><code>>()</code>
<code> </code><code>.Any((change) => (change.ConfigurationSettingName == configName)))</code>
<code> </code><code>{</code>
<code> </code><code>if(!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))</code>
<code> </code><code>{</code>
<code> </code><code>RoleEnvironment.RequestRecycle();</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>};</code>
<code> </code><code>});</code>
<code> </code><code>// For information on handling configuration changes</code>
<code> </code><code>return base.OnStart();</code>
<code> </code><code>public override void Run()</code>
<code> </code><code>CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");</code>
<code> </code><code>LocalResource localCache = RoleEnvironment.GetLocalResource("InstanceDriveCache");</code>
<code> </code><code>CloudDrive.InitializeCache(localCache.RootPath, localCache.MaximumSizeInMegabytes);</code>
<code> </code><code>// 檢查Container是否存在,不存在則建立</code>
<code> </code><code>CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();</code>
<code> </code><code>blobClient.GetContainerReference("drives").CreateIfNotExist();</code>
<code> </code><code>// 建立Cloud Drive</code>
<code> </code><code>myCloudDrive = storageAccount.CreateCloudDrive(</code>
<code> </code><code>blobClient</code>
<code> </code><code>.GetContainerReference("drives")</code>
<code> </code><code>.GetPageBlobReference("mydrive.vhd")</code>
<code> </code><code>.Uri.ToString()</code>
<code> </code><code>);</code>
<code> </code><code>try</code>
<code> </code><code>myCloudDrive.Create(64);</code>
<code> </code><code>catch (CloudDriveException)</code>
<code> </code><code>DriveLetter = myCloudDrive.Mount(0, DriveMountOptions.Force);</code>
<code> </code><code>base.Run();</code>
<code> </code><code>public override void OnStop()</code>
<code> </code><code>myCloudDrive.Unmount();</code>
<code> </code><code>base.OnStop();</code>
最後,修改配置檔案。在Cloud Service項目的ServiceConfiguration.cscfg中添加下列配置:
<code><?</code><code>xml</code> <code>version</code><code>=</code><code>"1.0"</code> <code>encoding</code><code>=</code><code>"utf-8"</code><code>?></code>
<code> </code><code><</code><code>Role</code> <code>name</code><code>=</code><code>"WebRole1"</code><code>></code>
<code> </code><code><</code><code>Instances</code> <code>count</code><code>=</code><code>"1"</code> <code>/></code>
<code> </code><code><</code><code>ConfigurationSettings</code><code>></code>
<code> </code><code><</code><code>Setting</code> <code>name</code><code>=</code><code>"Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"</code> <code>value</code><code>=</code><code>"UseDevelopmentStorage=true"</code> <code>/></code>
<code> </code><code><</code><code>Setting</code> <code>name</code><code>=</code><code>"DataConnectionString"</code> <code>value</code><code>=</code><code>"UseDevelopmentStorage=true"</code> <code>/></code>
<code> </code><code></</code><code>ConfigurationSettings</code><code>></code>
<code> </code><code></</code><code>Role</code><code>></code>
<code></</code><code>ServiceConfiguration</code><code>></code>
在ServiceDefinition.csdef中添加下列配置(注意将Sites部分的内容删除或注釋掉):
<code> </code><code><</code><code>WebRole</code> <code>name</code><code>=</code><code>"WebRole1"</code><code>></code>
<code> </code><code><</code><code>Sites</code><code>></code>
<code> </code><code><</code><code>Site</code> <code>name</code><code>=</code><code>"Web"</code><code>></code>
<code> </code><code><</code><code>Bindings</code><code>></code>
<code> </code><code><</code><code>Binding</code> <code>name</code><code>=</code><code>"Endpoint1"</code> <code>endpointName</code><code>=</code><code>"Endpoint1"</code> <code>/></code>
<code> </code><code></</code><code>Bindings</code><code>></code>
<code> </code><code></</code><code>Site</code><code>></code>
<code> </code><code></</code><code>Sites</code><code>></code>
<code> </code><code><</code><code>Endpoints</code><code>></code>
<code> </code><code><</code><code>InputEndpoint</code> <code>name</code><code>=</code><code>"Endpoint1"</code> <code>protocol</code><code>=</code><code>"http"</code> <code>port</code><code>=</code><code>"80"</code> <code>/></code>
<code> </code><code></</code><code>Endpoints</code><code>></code>
<code> </code><code><</code><code>Imports</code><code>></code>
<code> </code><code><</code><code>Import</code> <code>moduleName</code><code>=</code><code>"Diagnostics"</code> <code>/></code>
<code> </code><code></</code><code>Imports</code><code>></code>
<code> </code><code><</code><code>LocalResources</code><code>></code>
<code> </code><code><</code><code>LocalStorage</code> <code>name</code><code>=</code><code>"InstanceDriveCache"</code> <code>cleanOnRoleRecycle</code><code>=</code><code>"false"</code> <code>sizeInMB</code><code>=</code><code>"300"</code> <code>/></code>
<code> </code><code></</code><code>LocalResources</code><code>></code>
<code> </code><code><</code><code>Setting</code> <code>name</code><code>=</code><code>"DataConnectionString"</code> <code>/></code>
<code> </code><code></</code><code>WebRole</code><code>></code>
<code></</code><code>ServiceDefinition</code><code>></code>
步驟四:觀察并分析代碼
步驟三中的代碼中,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的盤符。