[Windows Azure] 在雲端執行你的命令列應用程式

  • 13057
  • 0
  • WCF
  • 2010-07-01

[Windows Azure] 在雲端執行你的命令列應用程式

最近很常被問的問題,不外乎是怎麼將現有應用程式移轉到 Windows Azure Cloud 上面,但其中有一種類型的問題,就是如果應用程式是非 Web 型的應用程式要如何移轉到雲端,比例最多的就是命令列應用程式 (Command-line application, Console Application),這些應用程式可能是舊有應用程式,也有可能是包裝了某些演算法 (例如 Matlab Application) 的應用程式,這些應用程式有些可能是沒有原始碼,有些也可能是移轉不方便或改寫會耗費太多時日,因此如果能夠將它直接移轉到 Windows Azure 雲端 VM 的話,對應用程式開發廠商來說是很棒的。

現在我可以告訴你,這個答案是肯定的,而且作法早在今年三月就已經有人提出。這次我在交大的課程間,也有不少學生來詢問這方面的問題,原訂要現場實作一支命令列程式給大家看的,但因時間來不及而作罷 … 而且關鍵的部份一直沒有方向,直到今天 Carol 寄來一個連結,令我茅塞頓開啊。

在 Windows Azure VM 中執行 Console Application 是一定可行的,而且作法也很簡單,只要用 Process 類別來啟動 Console Application 即可,但是關鍵的點是如何探知在雲端 VM 中應用程式被放在哪裡,這個變數在 Windows Azure SDK 中並沒有提及,同時它是在 VM 中的環境變數,名稱為 RoleRoot,它會傳回 Role 所在的磁碟機路徑。請注意,VM 中應用程式的路徑並不是在 C:\,而是在 %RoleRoot%\approot\ 中,所以不可以直接把路徑設死 (至少 RoleRoot 不可以設死)。另外,開發人員也需要在應用程式封裝中加入該可執行檔,如此檔案才可以被發布在雲端 VM。

多說無益,來個範例給大家看。

1. 首先,建立一個 console application,我使用的是很簡單的應用程式,這個應用程式可以傳回目前系統時間:

namespace TimeGenerator
{
    class Program
    {
        static void Main(string[] args)
        {
           
Console.Out.Write(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));
        }
    }
}

 

2. 建立一個雲端應用程式,並加入一個 Worker Role,我在這裡所建立的是 WCF 應用程式,並且利用 REST API 方式顯露方法,這個服務會啟動前面所建立的應 Console 應用程式,請注意 FileName 的設定,這是執行 Console 應用程式的最重要關鍵程式碼:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace TimeGeneratorService
{
    [ServiceContract]
    public interface ITimeGenerator
    {
        [OperationContract, WebGet]
        string GetCurrentTime();
    }

    class TimeGeneratorService : ITimeGenerator
    {
        public string GetCurrentTime()
        {
            Process p = new Process();
            p.StartInfo = new ProcessStartInfo()
            {
                FileName = Path.Combine(Environment.GetEnvironmentVariable("RoleRoot"), "approot", "TimeGenerator.exe"),
                RedirectStandardOutput = true,
                CreateNoWindow = true,
                UseShellExecute = false
            };
            p.Start();
            p.WaitForExit();

            string result = p.StandardOutput.ReadToEnd();
            p.Close();

            return result;
        }
    }
}

 

3. 將第一步所建立的應用程式加入到 Worker Role 的專案中,方法可以是直接在 Visual Studio 中使用 [加入 > 現有項目] 的方式,或是將執行檔複製到專案目錄,再由 Visual Studio 顯示所有檔案再加入專案的方式,但不論是哪種方式,都要確認該檔案的建置動作 (Build Action) 是內容 (Content),同時也要設定複製到輸出目錄 (Output Folder) 為永遠複製 (Copy always) 或是有更新時複製 (Copy if newer)

image

 

4. 在 Worker Role 進入點設定將服務掛載起來:

private WebServiceHost _serviceHost = null;

public override bool OnStart()
{
    // Set the maximum number of concurrent connections
    ServicePointManager.DefaultConnectionLimit = 12;

    DiagnosticMonitor.Start("DiagnosticsConnectionString");

    // For information on handling configuration changes
    // see the MSDN topic at
http://go.microsoft.com/fwlink/?LinkId=166357.
    RoleEnvironment.Changing += RoleEnvironmentChanging;

    this._serviceHost = new WebServiceHost(
        typeof(TimeGeneratorService), new Uri("
http://localhost:8080/"));
    _serviceHost.Open();

    return base.OnStart();
}

並在 app.config 中加入 WCF 的設定(這裡剛好也是 WCF 4.0 的 Simple Configuration 功能):

<system.serviceModel>
  <behaviors>
    <serviceBehaviors>
      <behavior>
        <serviceMetadata httpGetEnabled ="true"/>
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <protocolMapping>
    <add binding="wsHttpBinding" scheme ="http"/>
  </protocolMapping>
</system.serviceModel>

 

5. 按 F5 啟動 Visual Studio Debugger 以啟動 Development Fabric,並且在瀏覽器中輸入 http://localhost:8080/GetCurrentTime

image

image

 

瀏覽器回傳的會是由 Console Application 所傳回的時間。

 

Reference:
http://social.msdn.microsoft.com/Forums/en-IE/windowsazure/thread/2755d7c8-984a-43d4-9652-f6c82d8c4b2b
http://social.msdn.microsoft.com/Forums/en/windowsazure/thread/5bc5f411-5940-44ce-ac49-a3eb999bd51b