Windows Azure

在 Windows Azure 上針對消費型裝置建置大量可調整的平台

Bruno Terkaly
Ricardo Villalobos

下載代碼示例

本文主要介紹可縮放性和互通性,體系結構中需要這兩種特性來支援當今熱門移動平臺(使用者可能超過百萬)的多樣性。圖 1 描繪了這種多樣性,對於當下的開發人員來說,這是一種常見且具有挑戰性的場景。為移動設備提供基於 Web 的服務是一項令人畏縮的任務,因為它需要多種不同的工具、語言和 IDE。在這種多樣性的背後是對彈性縮放的需求,因為需要面對提供的眾多 Web 服務和 TB 級的資料。

圖 1 各種不同的移動技術對於開發人員是一項挑戰

應用程式類型 平臺 開發環境 語言
移動 Windows Phone Visual Studio C#
移動 Android Eclipse Java
移動 iOS Xcode Objective-C
基於雲的 Web 伺服器 Windows Azure Visual Studio C#

開發人員需要在兩個不同的維度上縮放他們的 Web 應用程式。第一個維度是計算,它僅壓縮到主機供應商提供的 Web 服務實例的數量,以回應移動 Web 請求。第二個維度是可縮放的資料:某些雲平臺通過專用存放裝置提供可縮放的資料,以允許開發人員縮放數百萬移動使用者的 TB 級資料,然後在多台伺服器上輕鬆進行分區,從而獲得 PB 容量快速的性能、冗余和支援。

要儘量對各種各樣用戶端通信提供支援,交互操作方案是必不可少的。從資料格式到網路通訊協定,每一個環節都需要仔細考慮。解決方案必須能最小化自訂編碼,並最大可能地使用開放標準。

在本文中,我們使用 Windows Azure(Microsoft 雲平臺)中託管的 RESTful Web 服務解決互通性挑戰和彈性縮放問題。

圖 2 描繪了基於 RESTful Web 服務的參考體系結構。RESTful 體系結構具有互通性,因為它們與 HTTP/1.x 一同開發並對大量的用戶端提供統一的通信。可以替代 REST 的體系結構是 SOAP。我們不選擇使用 SOAP 是因為它更大、資料負載更慢且更加複雜。

圖 2 基於開放標準的解決方案

使用 Windows Azure 便於根據需要增加和減少規模。僅僅通過使用 Windows Azure 門戶或管理 API 更改數位(即“實例計數”),幾乎就可以毫不費力地縮放 RESTful Web 服務以滿足任何層級的需要。

我們的實現使用 JSON(而非 XML)作為資料格式,因為它緊湊並廣泛受到支援。XML 存在負載較大的難題。

儘管許多供應商為 RESTful Web 服務提供雲託管解決方案,但是 Windows Azure 具有很多優勢。對於初學人員來說,你可以在位於亞洲、歐洲和北美的六個高自動化資料中心之間進行選擇,包括 24 個內容傳送網路 (CDN),以便以低延遲和低資料局部性連接使用者變為可能。

Windows Azure 提供了一組存儲和計算選項,另外還有功能強大的開發人員工具。各種各樣的存儲機制都可用,從二進位大型物件 (BLOB) 到關係存儲。Windows Azure 還提供身份管理系統、安全郵件和混合雲/本地連接功能。

開始使用

本文的剩餘內容將體系結構和實現分為四個部分:

  1. 使用 Windows Azure 門戶設置帳戶。
  2. 創建 Windows Azure 雲專案,並編寫一些代碼定義 RESTful Web 服務。
  3. 使用 Windows Azure 門戶將雲專案部署到帳戶。
  4. 為以下內容構建移動應用程式: Windows Phone, Android and iOS (iPhone/iPad).

讓我們一起來看看下麵這些步驟。第一個步驟在 Windows Azure 門戶中執行,如果你有訂閱,可以從 windows.azure.com 進行訪問。(有關詳細資訊,請訪問 azure.com。)

Part 1:在 Windows Azure 門戶中設置 Web 服務

Windows Azure 門戶中的兩個重要選項為:新建託管服務和新建存儲帳戶。

圖 3 展示了設置“託管服務”的工作流。該過程會生成一個 URL,代表部署 RESTful Web 服務的 Microsoft 資料中心的端點。Windows Phone、Android 和 iOS 應用程式開發人員將需要該 URL 與服務進行通信。

圖 3 設置 Windows Azure RESTful Web 服務

完成上述所有操作的工作流很簡單:

  1. 登錄 Windows Azure 門戶。
  2. 選擇“新建託管服務”。指定帳戶名、URL 和區域(資料中心的位置)。
  3. 存儲 Windows Azure 門戶生成的 URL;將在構建 RESTful Web 服務和移動用戶端時與帳戶名一起使用該 URL。帳戶名在第 3 部分還要用到。

Note:本文中的示例使用帳戶名“fastmotorcycleservice”以及 URL“http://fastmotorcycleservice.cloudapp.net.”

在 Windows Azure 門戶中的第二個任務是創建存儲帳戶。圖 4 展示了該過程,包括 Windows Azure 表的名稱和位置。現在還可以從六個數據中心內進行選擇。最好在同一個資料中心託管 Web 服務和資料,以降低成本和提高性能。

圖 4 設置 Windows Azure 存儲帳戶

工作流與之前介紹的“託管服務”相似:

  1. 登錄 Windows Azure 門戶。
  2. 創建新的存儲帳戶並提供帳戶名和區域。
  3. 存儲 Windows Azure 門戶生成的便捷鍵並提供帳戶名;在構建 RESTful Web 服務時將需要這兩項。

第 1 部分完成後,所需的 Windows Azure 門戶資訊可用於編寫 RESTful Web 服務以及 Windows Phone、Android 和 iOS 應用程式。

Part 2:構建 Windows Azure 託管的 RESTful Web 服務

在 Visual Studio 中構建 RESTful Web 服務很簡單。在“開始”|“所有程式”|“Microsoft Visual Studio 2010”中,按右鍵 Microsoft Visual Studio 2010 快捷方式並選擇“以管理員身份運行”,以便作為管理員打開 Visual Studio。從“檔”功能表中選擇“新建”|“專案”。

在“新建專案”對話方塊中,展開“已安裝的範本”清單中的首選語言並選擇“雲”。選擇 Windows Azure 專案範本,將專案名稱設置為 FastMotorcycleProject,並將位置設置為方便的任何地點。

下麵的網址提供了詳細介紹這些步驟的視頻:bit.ly/VideoAzureRestfulService

解決方案資源管理器如圖 5 所示。

圖 5 創建新的 Windows Azure 專案

圖 6 顯示本文未涉及的一些基本步驟(但在參考視頻中有介紹)。

圖 6 本文未涉及的基本步驟

視頻仲介紹的任務 備註
Adding an ASP.NET Web Role 將用於託管 RESTful Web 服務
Adding a DataConnectionString 將包括帳戶名和便捷鍵
添加某些基本啟動代碼以初始化資料 將代碼添加到 global.asax.cs 以讀取 DataConnectionString

這些步驟在所有 Windows Azure 專案中很常見。例如,使用 Web 角色託管 RESTful Web 服務是一種標準做法。需要 DataConnectionString 以訪問之前在 Windows Azure 門戶中定義的存儲帳戶。Visual Studio 專案中需要啟動代碼從設定檔讀取帳戶名和便捷鍵,以用於存儲帳戶。

完成最初的步驟後,可以使用 Visual Studio 中的 WCF 服務範本添加 RESTful Web 服務。

要添加 WCF 服務,請按右鍵 FastMotorcycleProject_WebRole 資料夾,選擇“添加”|“新建專案”對話方塊,並將類名稱設置為 FastMotorcycleService。

隨即生成 FastMotorcycleService.svc.cs。使用圖 7 中所示的代碼取代類的整個代碼。

讓此操作生效的關鍵在於知道如何映射不同的 URI 和 RESTful 方法的謂詞。為此,必須將 WebGet 和 WebInvoke 屬性添加到圖 7 的代碼中。

圖 7 FastMotorcycleListService.svc.cs

[ServiceContract]
public class FastMotorcycleListService
{
  private FastMotorcycleListDataProvider _data;
  
  public FastMotorcycleListService()
  {
    _data = new FastMotorcycleListDataProvider();
  }

  [OperationContract]
  [WebGet(UriTemplate = "/list/{owner}", ResponseFormat = 
    WebMessageFormat.Json)]
  public List<string> GetItems(string owner)
  {
    return _data.GetItems(owner);
  }

  [OperationContract]
  [WebInvoke(UriTemplate = "/list/{owner}", Method = "POST",
    RequestFormat = WebMessageFormat.Json)]
  public void AddItem(string owner, string item)
  { 
    _data.AddItem(owner, item);
  }

  [OperationContract]
  [WebInvoke(UriTemplate = "/list/{owner}/{item}", Method = "DELETE")]
  public void DeleteItem(string owner, string item)
  {
    _data.DeleteItem(owner, item);
  }
}

這些屬性告訴框架方法應該回應 HTTP GET 請求。預設情況下,WebInvoke 映射到 HTTP POST。同樣在預設情況下,URI 由方法的名稱(已添加到端點的基 URI)確定。某些專家或 REST 純粹主義者可能會說我們的方法名稱不應是動詞,而應是名詞。

圖 8 所示的 WCF REST 程式設計模型允許為每個方法自訂 URI,具體操作是使用可在 WebInvoke 或 WebGet 屬性上通過 UriTemplate 屬性設置的範本。該模型將在以下清單仲介紹,其數位與圖 8 中的數位對應:


圖 8 移動應用程式請求 RESTful 資料的工作流

  1. 移動應用程式使用標準 HTTP 發送消息請求,請求中包括一個 HTTP 謂詞和一個 URL。
  2. RESTful Web 服務截獲移動應用程式消息請求(資料請求)並調用 GetItems,傳遞“Bruno”作為參數。GetItems 使用 LINQ 查詢來查詢資料,並使用“Bruno”作為 where 子句的一部分。
  3. 僅從 Windows Azure 表服務中返回 PartitionKey 等於“Bruno”的記錄。
  4. 資料會轉換為 JSON 格式(自動)並返回給移動設備。
  5. 資料可用於移動應用程式。資料用於填充 ListBox 並呈現給移動應用程式使用者。

下麵我們討論的三個類是説明程式物件,需要用它們來與 Windows Azure 表服務進行交互。Fast­MotorcycleListDataProvider、FastMotorcycleListItem 和 FastMotorcycleList 是從圖 9 的代碼中提取存儲和 Windows Azure 表特定 API 詳細資訊的類,允許應用程式使用 Windows Azure 表服務執行創建、讀取、更新和刪除 (CRUD) 操作。

在 Visual Studio 中,添加一個名為 FastMotorcycleListDataProvider.cs 的新類別模組。使用圖 9 中的代碼替換該代碼。

圖 9 FastMotorcycleListDataProvider、FastMotorcycleListItem 和 FastMotorcycleList 類

public class FastMotorcycleListDataProvider
{
  private FastMotorcycleList _list;

  public FastMotorcycleListDataProvider()
  {
    string configValue = RoleEnvironment.GetConfigurationSettingValue(
      "DataConnectionString");
    var account = CloudStorageAccount.Parse(configValue);

    _list = new FastMotorcycleList(account.TableEndpoint.ToString(),
                                   account.Credentials);
  }
 
  public List<string> GetItems(string owner)
  {
    var results = from entity in _list.Items
                  where entity.PartitionKey == owner
                  select entity;

    var list = new List<string>();
    foreach (var item in results)
    {
      list.Add(item.RowKey);
    }

    return list;
  }
 
  public void AddItem(string owner, string item)
  {
    _list.AddObject("FastBikes", new FastMotorcycleListItem(owner, item));
    _list.SaveChanges();
  }

  public void DeleteItem(string owner, string item)
  {
    var entity = (from i in _list.Items
                  where i.PartitionKey == owner
                  && i.RowKey == item
                  select i).Single();

    _list.DeleteObject(entity);
    _list.SaveChanges();
  }
}

 
public class FastMotorcycleListItem : TableServiceEntity
{
  public FastMotorcycleListItem()
  {
  }
 
  public FastMotorcycleListItem(string partitionKey, string rowKey)
    : base(partitionKey, rowKey)
  {
  }
}
 
public class FastMotorcycleList : TableServiceContext
{
  public FastMotorcycleList(string baseAddress,
    StorageCredentials storageCredentials)
    : base(baseAddress, storageCredentials)
  {
  }
 
  public DataServiceQuery<FastMotorcycleListItem> Items
  {
    get
    {
      return this.CreateQuery<FastMotorcycleListItem>("FastBikes");
    }
  }
}

Part 3:部署 RESTful Web 服務

這是 Windows Azure 可以真正炫耀的領域之一。 部署 100 個 RESTful Web 服務實例如同部署一個實例一樣簡單。 請注意下麵的步驟清單:

  1. 在 Visual Studio 中,按右鍵 FastMotorcycleProject 並選擇“打包”。
  2. 使用流覽器返回門戶並選擇“託管服務、存儲帳戶和 CDN”。
  3. 在頂部窗格中,選擇“託管服務”。
  4. 在中間窗格中,選擇你之前創建的託管服務。
  5. 按右鍵並選擇“新建生產部署”,上載檔(FastMotorcycleProject.cspkg 和 ServiceConfiguration.Cloud.cscfg);這些檔是在第一步中生成的。

Part 4:從移動應用程式使用 RESTful Web 服務

現在我們將討論從各種移動應用程式使用 RESTful Web 服務。 本部分旨在重點介紹這種方法提供的互通性。

JSONKit (github.com/johnezang/JSONKit) 使得從 iOS 設備與 RESTful Web 服務的交互更為簡單。 只需幾行代碼,就可以完成以下操作:調用 RESTful Web 服務,下載 JSON 格式化的資料,將資料轉換為更好用的格式並將轉換的資料附加到表視圖控制項,再由 iPhone 或 iPad 應用程式使用(參見圖 10)。

圖 10 解析 JSON 資料的 Objective-C 代碼

NSString *username = @"Bruno"; // Gets passed to the RESTful Web Service
  
NSString *serviceUri = "http://your_hosted_service_name.cloudapp.net/"+
  "FastMotorcycleListService.svc/list/";
// Build the service URI (will point to our RESTful Web service
NSString *url = [NSString stringWithFormat:@"%@%@", serviceUri, username];
      
// Retrieve the data in the form of a JSON array
NSData *json = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
     
// Convert from JSON array to NSArray
// This allows us to populate the table view more easily
NSArray *itemArray = [json objectFromJSONData];
     
// Assign the array to the TableView
// fastbikes is the name of our TableView control
self.fastbikes = [[NSMutableArray alloc] initWithArray:itemArray];

開發 Android 涉及到 Java 程式設計語言,該語言已經問世很長時間,並可在本機解析 JSON 資料。 圖 11 顯示了一個示例。 Windows Phone SDK 包括本機支援以調用 RESTful Web 服務和處理 JSON 格式化的資料。 SDK 使得使用 DataContractJsonSerializer 處理 JSON 資料變得簡單。 圖 12 顯示了一個示例。 最後,如果你想要瞭解開發 Android 和 iOS 的功能更強大的工具包,請訪問 Microsoft 認可的以下連結:github.com/microsoft-dpe

圖 11 解析 JSON 資料的 Android 代碼

    // HttpClient used to talk to Web service
    HttpClient httpclient = new DefaultHttpClient();
                  
    String url = 
      "http://your_hosted_service_name.cloudapp.net/"+
      "FastMotorcycleListService.svc/list/Bruno";
    // This will be the array we need to convert
    // We get the data from the Web service
    JSONArray listItems = null;
    String jason = null;
                  
    // Set up the RESTful call to 'GET' the data
    HttpGet request_http_get = new HttpGet(url);
      
                  
    // Read the JSON data and assign it to ListView
    try 
    {
      // Fill a response object using a request
      HttpResponse response_http_get = httpclient.execute(request_http_get);
                
      // Length represents the number of data items returned
      // by RESTful Web service
      long length = response_http_get.getEntity().getContentLength();
    
      // "entity" ends up being the data coming back from Web server
      HttpEntity entity = response_http_get.getEntity();
     
      // Read the bytes, one byte at a time
      InputStream stream = entity.getContent();
                     
      // Allocate a series of bytes
      byte[] buffer = new byte[(int) length];
                    
      // Read bytes from RESTful Web service
      // After this loop, we end up with something like -> 
      // ["busa","gxr1000","ninja250"]
      for (int i = 0; i < length; i++) 
      {
        buffer[i] = (byte) stream.read();
      }
      // Create an array of strings
      jason = new String(buffer);
      // Convert to JSON array for Android ListBox
      // listItems ends up being a three-element JSON array (see "busa")
      listItems = new JSONArray(jason);
      } 
      catch (Exception e) 
      {
        System.out.println(e);
      }

圖 12 解析 JSON 資料的 C# 代碼

private void LoadList()
{
  string uri =   
    @"http://your_hosted_service_name.cloudapp.net/"+
    "FastMotorcycleListService.svc/list/Bruno";
  var webRequest = (HttpWebRequest)WebRequest.Create(uri);
  webRequest.Method = "GET";
 
  try
  {
    webRequest.BeginGetResponse(new AsyncCallback((result) =>
    {
      var webResponse = 
        (HttpWebResponse)webRequest.EndGetResponse(result);
  
      if (webResponse.StatusCode == HttpStatusCode.OK)
      {
        var jsonDeserializer = 
          new DataContractJsonSerializer(typeof(List<string>));
        List<string> items = 
          (List<string>)jsonDeserializer.ReadObject(
          webResponse.GetResponseStream());                      

        shoppingListBox.Dispatcher.BeginInvoke(new Action(() =>
        {
          shoppingListBox.Items.Clear();
          foreach (var item in items)
          {
            shoppingListBox.Items.Add(item);
          }
        }));
      }

    }), null);
  }
  catch
  {
     // Ignored
  }
}

訪問設備的整個家族

由於 Windows Azure 託管的 RESTful Web 服務基於 HTTP,因此支援該協定的任何用戶端應用程式都可以與它進行通信。 這為開發人員打開了設備大門,眾多設備可任意挑選,因為大多數設備都支援 HTTP 協定。 儘管我們在本文中討論的是移動平臺,但是諸如 jQuery 的 JavaScript 實現也可以使用 RESTful Web 服務。 無論移動平臺針對 UI 多樣性採取什麼途徑,構建簡單、開放且基於 HTTP Web 服務的體系結構總是有意義的。

Bruno Terkaly 是 Microsoft 的開發推廣人員。他的知識深度來源於多年來相關領域以及使用大量平臺、語言、框架、SDK、庫和 API 編寫代碼的經驗。他不辭辛苦,就有關構建基於雲的應用程式(特別是使用 Windows Azure 平臺)編寫代碼、發佈博客並給予現場演示。

Ricardo Villalobos 是一名資深的軟體設計師,具有 15 年為供應鏈管理行業設計和創建應用程式的經驗。他持有多個不同的 Microsoft 證書,並獲得了達拉斯大學供應鏈管理專業的 MBA 學位。他于 2010 年進入 Microsoft 並成為一名 Windows Azure 架構推廣人員。

衷心感謝以下技術專家對本文的審閱:Reza AlizadehWade Wegner