運用 Windows Azure Cloud Services 的 Startup Tasks 設定地區與語言
為了延展性的考量,Windows Azure Cloud Services 並不會保存本機硬碟的狀態與設定,也因此所有對於系統環境的設定與軟體環境安裝都必須借助 Startup Tasks,讓虛擬機器啟動時自動執行些工作。欲使用 Windows Azure Cloud Services Startup Task 必須在 Windows Azure Service Definition Schema (.csdef File). 內做相關的宣告。https://msdn.microsoft.com/en-us/library/windowsazure/gg456327.aspx 內有詳細的描述,例如我希望虛擬機器一啟動時便以系統管理員身分執行一個名為 global.cmd 的批次檔,並等待此批次檔執行完畢之後方可繼續執行,您可以在 ServiceDefinition.csdef 內加上下面 XML 宣告:
< ServiceDefinition name="MyService" xmlns="https://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
< WebRole name="WebRole1">
< Startup>
<Task commandLine="global.cmd" executionContext="elevated" taskType="simple">
</Task>
</Startup>
</WebRole>
< /ServiceDefinition>
但如何在 Starup Tasks 內設定地區與語言 (Regional and Language Options) 為台灣呢? 這件事情比想像中麻煩些。目前 (2012 年 10 月) Windows Azure Cloud Services 內虛擬機器的 Windows Azure Guest OS 作業系統是 Windows Server 2008 或 Windows Server 2008 R2,Windows Server 2008 支援 PowerShell 1.0,而 Windows Server 2008 R2 則支援 PowerShell 2.0。這兩個版本的 Powershell 之內都沒有支援地區與語言的設定,因此要取代手動在控制台內設定地區與語言,需要採用其他的方法。
在 Windows XP 時代,即可透過命並列來進行地區與語言的設定,此方法最後的更新的文件是在 Windows Vista 時的 https://msdn.microsoft.com/en-ie/goglobal/bb964650%28en-us%29.aspx,例如我們可以將欲設定的地區與語言描述於 locale.xml 中,並在命令列內透過控制台 control.exe 加以執行與設定
control.exe intl.cpl,,/f:"locale.xml"
要將格式與地區都設定為台灣,可以提供以下的 locale.xml
<gs:GlobalizationServices xmlns:gs="urn:longhornGlobalizationUnattend">
<!--User List-->
<gs:UserList>
<gs:User UserID="Current" CopySettingsToDefaultUserAcct="true" CopySettingsToSystemAcct="true"/>
</gs:UserList>
<!--User Locale, change to Taiwan-->
<gs:UserLocale>
<gs:Locale Name="zh-TW" SetAsCurrent="true"/>
</gs:UserLocale>
<!--location, change to Taiwan ,GeoID of Taiwna is 237 -->
<gs:LocationPreferences>
<gs:GeoID Value="237"/>
</gs:LocationPreferences>
< /gs:GlobalizationServices>
XML 內的 CopySettingsToSystemAcct="true" 設定十分重要,因為即便將目前的系統管理員帳號區域設定修改成台灣,並不會將啟動 IIS 的系統帳號 NT AUTHORITY\NETWORK SERVICE 的地區與語言設定一併修改成台灣,必須將 CopySettingsToSystemAcct="true" 方會將主要系統帳號做相同的設定。
可以在 Windows Server 2008 R2 命令列模式中順利執行control.exe intl.cpl,,/f:"locale.xml" 並不代表事情已經完成,我們必須將這個命令加入進 Windows Azure Cloud Services Startup Task 之中。由於這個區域設定的動作會干擾到虛擬機器啟動過程,因此我將 taskType="background” 改為在虛擬機器啟動的同時在背景同時執行區域設定的批次檔 global.cmd。此外,這個 Startup Task 也會干擾開發環境的模擬器,讓開發環境無法順利將程式佈署到 Windows Azure Compute Emulator 模擬器,因此ServiceDefinition.csdef 內加上下面 XML 宣告:
<WebRole name="WebRole1" vmsize="Small">
<Startup>
< Task commandLine="global.cmd" executionContext="elevated" taskType="background">
<Environment>
< Variable name="EMULATED">
< RoleInstanceValue xpath="/RoleEnvironment/Deployment/@emulated" />
</Variable>
</Environment>
</Task>
</Startup>
</WebRole>
並讓 Starup Task 的批次檔 global.cmd 內做個判斷,若是在開發環境 Windows Azure Compute Emulator 模擬器中執行時,不去執行 control.exe intl.cpl,,/f:"locale.xml" ,此外為了記錄可能錯誤訊息與命令列的輸出訊息,我們也可以將命令列執行的輸出導入到兩個文字檔的 log 中,以備不時之需。
if "%EMULATED%"=="true" goto :EOF
control.exe intl.cpl,,/f:"locale.xml" >> StartupTasklog.txt 2>> StartupTaskErrorlog.txt
請記得要將 global.cmd 與配合的 locale.xml 置放在 [您的 AppRoot]\Bin 的資料夾之內,並別忘了這兩個檔案在 Visual Studio 內檔案屬性設定時要設為 Copy always。
我們可以用個簡單的 ASP.NET Web form 應用程式測試是否設定成功。
using System.Threading;
using System.Globalization;
…
protected void Button1_Click(object sender, EventArgs e)
{
string curCultureName;
string curCultureNativeName;
string curUserName;
curCultureName = Thread.CurrentThread.CurrentCulture.Name;
curCultureNativeName = Thread.CurrentThread.CurrentCulture.NativeName;
curUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
this.Label1.Text = curCultureName;
this.Label2.Text = curCultureNativeName;
this.Label3.Text = curUserName;
}
在順利佈署完此 Web Role 後執行正常,大功告成。