8 る 2015

第 30 卷,第 8 期

本文章是由機器翻譯。

雲計算連接的移動應用程式-與蔚藍的 Web 應用程式和 WebJobs 創建的 Web 服務

Erik Reitan

今天,許多移動應用程式連接到提供寶貴和有趣的資料的一個或多個 Web 服務。當設計和開發此類應用程式,採取最簡單的方法是對這些服務的直接 REST API 呼叫,然後處理在用戶端的回應。然而,這種方法有很多缺點。其一,每一個網路電話、 每一位用戶端處理消耗珍貴的電池功率和頻寬。此外,廣泛的用戶端的處理可以需要一段時間,若要執行,尤其是在低端硬體,使應用程式的反應較小。不同的 Web 服務可能會限制節流,這意味著純用戶端的解決方案將不容易擴展到更多的使用者。

因此,它在許多情況下有意義 — — 尤其是那些從多個源提取資料 — — 若要創建您自己的後端,指你可以卸載某些任務。作為我們的工作在微軟作為一個團隊來為ASP.NET、 微軟 Azure 和Visual Studio中的跨平臺開發工具開發內容的一部分,我們創建了一個具體的例子,這種方法。

在這兩部分的文章中,我們討論了我們的方法,我們所遇到的挑戰和一些我們開發我們的應用程式時的經驗教訓。此應用程式,我們命名為"高層"(一種有趣的雲),搜索堆疊溢位和 Twitter 的特定主題,我們稱之為"對話"。我們之所以選擇這兩個機構,因為他們都有好的 Web Api。應用程式有兩個主要元件:

  • 一朵雲回結束,主辦在 Azure 上。定期向供應商發出請求和聚合資料的表單,最適合於用戶端到後端。這避免了節流問題、 減少關於延遲提供程式中的任何疑慮、 最小化用戶端處理和減少網路請求從用戶端。一個代價是 WebJob 運行每隔幾小時,所以你不要即時資料。
  • 一個羽量級的移動用戶端應用程式,創建的 Xamarin,運行于 Windows、 Android 和 iOS (見圖 1)。移動用戶端從後端獲取聚合的資料並呈現給使用者。它也保持同步的資料緩存在本機資料庫中好的離線體驗和更快的啟動時間。

Xamarin 手機用戶端上運行安卓平板電腦 (左)、 Windows Phone (中間) 和 iPhone (右)
圖 1 Xamarin 手機用戶端上運行安卓平板電腦 (左)、 Windows Phone (中間) 和 iPhone (右)

使用社會供應商 (谷歌或 Facebook) 的移動用戶端時,使用者可以選擇簽名。當登錄後,使用者可以設置進一步優化與用戶端通信的首選項。具體來說,他們可以選擇接收哪個學科領域和在每個主題領域內的對話的最大數目。使用者首選項存儲在後端,這樣使用者就可以從任何用戶端在登錄並獲得相同的體驗。為了證明這一想法,我們還創建了會談到同一後端的一個簡單的 Web 用戶端。

作為此專案的一部分,我們也想要使用內置Visual Studio和Visual Studio連線的應用程式生命週期管理 (ALM) 工具來管理衝刺和工作積壓,並執行自動化的單元測試,持續集成 (CI) 和連續部署 (CD)。

這兩部分的文章探討了我們專案的詳細資訊。第 1 部分側重于我們使用 ALM 工具 (DevOps) 和後端。我們講的也是我們所遇到的挑戰和一些教訓教訓,如:

  • 如何安全地自動密碼非 Web 應用程式的部署。
  • 如何處理蔚藍自動化超時。
  • 高效和翔實的幕後處理。
  • CI/CD 限制以及解決方法。

第 2 部分將討論如何使用 Xamarin 來多平臺移動用戶端,包括身份驗證和維護資料同步的用戶端緩存。

架構

圖 2 展示高層解決方案的高級體系結構。

  • 在後端,我們使用 Azure 應用程式服務承載的 Web 應用程式和 Azure SQL 資料庫來存儲在關係資料庫中的資料。我們使用Entity Framework(EF) 進行資料訪問。
  • 我們使用 Azure WebJobs 運行計畫的背景工作來從堆疊溢位和 Twitter 聚合資料並將它寫入到資料庫。WebJob 很容易可以從其他來源聚合資料擴展。
  • 移動用戶端使用 Xamarin 創建並與後端使用一個簡單的 REST API 進行通信。
  • REST API 是使用ASP.NETWeb API,它是一個框架,在 Microsoft.NET 框架中創建 HTTP 服務實現的。
  • Web 用戶端是一個相對簡單的 JavaScript 應用程式。我們使用 KnockoutJS 庫資料繫結和 jQuery 的 AJAX 調用。

高層體系結構
圖 2 高層體系結構

資料庫架構

我們使用 EF 代碼第一次來定義資料庫架構和管理後端 SQL 資料庫。作為圖 3 所示,該資料庫存儲以下實體:

  • 供應商:資料來源,如 Twitter 或堆疊溢位。
  • 對話:提供程式的項。對於堆疊溢位,這對應于一個問題的答案。對於 Twitter,它對應于一條微博。(這也可能是一條 tweet 的答覆,但我們並不實現該功能)。
  • 類別:主題的一次談話,如"Azure"或"ASP.NET"。
  • 標籤:為一個特定的類別和供應商的搜索字串。這些對應的標記在堆疊溢位 ("azure--網站") 和雜湊標記在 Twitter ("#azurewebsites")。後端使用這些查詢提供程式。最終使用者不會看到他們。
  • UserPreference:存儲每個使用者首選項。
  • UserCategory:UserPreference 和類別定義一個聯合資料表。

高層資料模型
圖 3 高層資料模型

一般來說,創建、 讀取、 更新、 刪除 (CRUD) 高層應用程式中的代碼是典型的 EF 代碼優先。一個特別考慮已做處理資料庫播種和遷移。代碼首先創建和種子一個新的資料庫,如果不存在任何資料庫程式試圖訪問資料的第一次。因為第一次嘗試訪問資料可能發生在 WebJob,我們要在代碼的 WebJob 的主要方法,使 EF 使用 MigrateDatabase­ToLatestVersion 初始值設定項:

static void Main()
{
  Task task;
  try
  {
    Database.SetInitializer<ApplicationDbContext>(
      new MigrateDatabaseToLatestVersion<ApplicationDbContext,
        Altostratus.DAL.Migrations.Configuration>());

沒有此代碼中,WebJob 會在預設情況下,沒有種子資料庫使用 CreateDatabaseIfNotExists 初始值設定項。當應用程式試圖從空表中讀取資料,則將會被一個空的資料庫和錯誤。

設計 WebJob

WebJobs 為正在運行的背景工作,提供了一個理想的解決方案,這是以前需要專用的 Azure 工作者角色,才能執行的工作。你可以在無需額外成本 Azure Web 應用程式上運行 WebJobs。你可以閱讀關於 WebJobs 提供在工作者角色在特洛伊狩獵篇博客文章的優點,"蔚藍 WebJobs 是多麼的偉大和你應該開始使用他們的權利,現在!"(bit.ly/1c28yAk)。

我們的解決方案為 WebJob 會定期運行三個功能:獲取 Twitter 資料、 獲取堆疊溢位資料並清除舊資料。這些函數是獨立的但他們必須按順序運行,因為它們共用相同的 EF 上下文。WebJob 完成,Azure 門戶顯示的每個函數狀態後 (見圖 3)。如果函數完成,它用一條綠色的成功消息,標記,如果發生異常,將標有紅色的失敗消息。

失敗不是少有在高層的因為我們使用免費的堆疊溢位和 Twitter 提供 Api。尤其是,查詢,是有限的:如果你超過查詢限制,提供程式將返回一個節流的錯誤。這是一個關鍵的原因,為創建後端放在第一位。雖然它將直接為移動應用程式,直接向這些供應商提出的要求,越來越多的使用者能迅速達到節流限制。相反後, 端可以使幾個定期請求收集和聚合資料。

我們遇到的一個問題是各地 WebJob 錯誤處理。通常情況下,如果在 WebJob 中的任何函數將引發異常,終止該 WebJob 實例,其餘功能不運行和整個 WebJob 運行標記為失敗。為了運行的所有任務和顯示功能級故障,WebJob 必須捕獲異常。如果任何函數 Main 中的拋出,我們記錄的最後一個異常和重新拋出,所以 WebJob 獲取標記為失敗。中的偽代碼圖 4 顯示這種方法。(專案下載包含完整的代碼)。

圖 4 捕捉並再次引發異常

static void Main()
{
  Task task;
  try
  {
    Exception _lastException = null;
    try
    {
      task = host.CallAsync("Twitter");
      task.Wait();
    }
    catch (Exception ex)
    {
      _lastException = ex;
    }
    try
    {
      task = host.CallAsync("StackOverflow");
      task.Wait();
    }
    catch (Exception ex)
    {
      _lastException = ex;
    }
    task = host.CallAsync("Purge Old Data");
    task.Wait();
    if (_lastException != null)
    {
      throw _lastException;
    }
  }
  catch (Exception ex)
  {
  }
}

圖 4,只有最後的一個特例展出了 WebJob 級。在函數級別,每個異常記錄,所以無一例外都將丟失。圖 5 成功地跑了 WebJob 顯示儀表板。您可以深入到每個函數以查看診斷輸出。

成功 WebJob 運行
圖 5 成功 WebJob 運行

設計 REST API

手機應用程式與後端通過一個簡單的 REST API,我們使用ASP.NETWeb API 2 實現通信。 (請注意,在ASP.NET5,Web API 合併到 MVC 6 框架,簡化合並兩個入一個 Web 應用程式)。

圖 6 總結了我們的 REST API。

圖 6 其他 API 摘要

獲取 api/類別 獲取的類別。
得到的 api 談話嗎? 從 = iso 8601 日期 獲取會話。
獲取 api/點擊 獲取使用者的首選項。
把 api/點擊 更新使用者的首選項。

所有的回答都是 JSON 格式。例如, 圖 7 顯示 HTTP 回應的談話。

圖 7 HTTP Response 的對話

HTTP/1.1 200 OK
Content-Length: 93449
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/8.0
Date: Tue, 21 Apr 2015 22:38:47 GMT
[
  {
    "Url": "http://twitter.com/815911142/status/590317675412262912",
    "LastUpdated": "2015-04-21T00:54:36",
    "Title": "Tweet by rickraineytx",
    "Body": "Everything you need to know about #AzureWebJobs is here.
      <a href=\"http://t.co/t2bywUQoft\"">http://t.co/t2bywUQoft</a>",
    "ProviderName": "Twitter",
    "CategoryName": "Azure"
  },
  // ... Some results deleted for space
]

交談中,我們不需要請求進行身份驗證。這意味著手機的應用程式可以始終顯示有意義的資料,而無需使用者登錄第一。但我們也想要證明有執行額外的優化,當使用者登錄時的後端。 我們的用戶端應用程式允許使用者選擇哪些類別的談話顯示,會話限制。所以如果一個請求進行身份驗證 (即登錄到應用程式的使用者) 後, 端自動篩選基於這些首選項的回應。這就限制了的必須由用戶端,這樣,隨著時間推移,減少了頻寬、 記憶體、 存儲和電池電源的要求處理的資料量。

對話 API 也採用一個可選的"從"參數在查詢字串中。如果指定,這篩選結果,包括只更新在該日期之後的對話:

GET api/conversations?from=2015-04-20T03:59Z

這最小化回應的大小。我們的移動用戶端使用此參數來要求只需要同步其緩存中的資料。

我們可以設計要使用查詢字串來溝通基於每個請求,使用者的首選項的 API 意味著這些首選項將僅在用戶端保持不變。這將避免需要進行身份驗證。而對於基本的方案,這種方法會做工精細,我們想要提供一個示例,可以擴展到更複雜的情況下查詢字串不足。在後端存儲首選項也意味著他們自動應用於每個用戶端相同的使用者的登錄。

資料傳輸物件 (Dto)

REST API 是資料庫架構和線表示之間的邊界。我們不想直接序列化的 EF 模型:

  • 它們包含用戶端不需要像外鍵的資訊。
  • 他們可以使 API 容易受到過度的過帳。(過度過帳時,客戶機更新你沒有縮進以公開更新的資料庫欄位。當你一個 HTTP 要求有效負載直接轉換成 EF 模型沒有充分驗證輸入,它會發生。請參閱 bit.ly/1It1wl2 更多的資訊.)
  • EF 模型的"形狀"專為創建資料庫表,並不是最佳的用戶端。

因此,我們創建了一整套資料傳輸物件 (Dto),只是 C# 類,定義 REST API 回應的格式。例如,下面是我們 EF 模型類別:

public class Category
{
  public int CategoryID { get; set; }
  [StringLength(100)]
  public string Name { get; set; }  // e.g: Azure, ASP.NET
  public ICollection<Tag> Tags { get; set; }
  public ICollection<Conversation> Conversations { get; set; }
}

類別實體具有一個主鍵 (類別 id) 和導覽屬性 (標記和對話)。導覽屬性可以很容易地跟隨在 EF 的關係 — — 例如,要查找所有標記為某一類別。

當用戶端請求的類別時,它只需要一個類別名稱清單:

[ "Azure", "ASP.NET" ]

這種轉換很容易執行 Web API 控制器方法中使用LINQSelect 語句:

public IEnumerable<string> GetCategories()
{
  return db.Categories.Select(x => x.Name);
}

UserPreference 實體是一個比較複雜一點的:

public class UserPreference
{
  // FK to AspNetUser table Id   
  [Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
  public string ApplicationUser_Id { get; set; }
  public int ConversationLimit { get; set; }    
  public int SortOrder { get; set; }            
  public ICollection<UserCategory> UserCategory { get; set; }
  [ForeignKey("ApplicationUser_Id")]
  public ApplicationUser AppUser { get; set; }
}

ApplicationUser_Id 是使用者表的外鍵。UserCategory 指向聯合資料表,創建使用者首選項和類別之間的多對多關係。

這裡就是我們想此尋到用戶端:

public class UserPreferenceDTO
{
  public int ConversationLimit { get; set; }
  public int SortOrder { get; set; }
  public ICollection<string> Categories { get; set; }
}

這隱藏實現細節的資料庫架構,如外鍵和聯合資料表的事情,並且蛻變成了一個字串清單的類別名稱。

LINQ運算式將轉換為 UserPreference UserPreference­DTO 是相當複雜,所以我們用 AutoMapper 來代替。AutoMapper 是一個映射物件類型的庫。這樣做是為了定義一個映射一次,然後使用 AutoMapper 來做你的映射。

當應用程式啟動時,我們將配置 AutoMapper:

Mapper.CreateMap<Conversation, ConversationDTO>();
Mapper.CreateMap<UserPreference, UserPreferenceDTO>()
  .ForMember(dest => dest.Categories,
             opts => opts.MapFrom(
               src => src.UserCategory.Select(
                 x => x.Category.Name).ToList()));
              // This clause maps ICollection<UserCategory> to a flat
              // list of category names.

CreateMap 第一次調用映射到 ConversationDTO,使用 AutoMapper 的預設映射約定的談話。為 UserPreference,映射是不那麼簡單,所以還有一些額外的配置。

一旦配置了 AutoMapper,物件的映射是很容易:

var prefs = await db.UserPreferences
  .Include(x => x.UserCategory.Select(y => y.Category))  
  .SingleOrDefaultAsync(x => x.ApplicationUser_Id == userId);
var results = AutoMapper.Mapper.Map<UserPreference,
  UserPreferenceDTO>(prefs);

AutoMapper 是足夠聰明,把它轉換成LINQ語句,所以選擇發生在資料庫上。

驗證與授權

我們使用社會的登錄 (谷歌和 Facebook) 使用者進行身份驗證。(將在這篇文章的第 2 部分詳細描述身份驗證過程)。Web API 認證後­enticates 請求,Web API 控制器可以使用此資訊來授權請求,查找使用者資料庫中的使用者。

若要限制授權使用者一個 REST API,我們裝飾控制器類的 [授權] 屬性:

[Authorize]
public class UserPreferencesController : ApiController

現在如果一個請求到 api/點擊不授權,Web API 自動返回 401 錯誤:

HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
WWW-Authenticate: Bearer
Date: Tue, 21 Apr 2015 23:55:47 GMT
Content-Length: 68
{
  "Message": "Authorization has been denied for this request."
}

請注意,Web API 添加 WWW 身份驗證標頭到回應。這就告訴用戶端支援哪種類型的身份驗證方案 — — 在這種情況下,OAuth2 持票人權杖中。

預設情況下,[授權] 假定還授權每個經過身份驗證的使用者,並且只有匿名請求被阻止。你也可以將授許可權制為使用者在指定的角色 (如管理員),或執行自訂授權篩選器更複雜的授權情況。

對話 API 是更有趣的例子:我們允許匿名請求,但請求進行身份驗證時,將應用額外的邏輯。下面的代碼檢查是否當前請求進行身份驗證,是否是這樣,從資料庫中獲取使用者首選項:

if (User.Identity.IsAuthenticated)
{
  string userId = User.Identity.GetUserId();
  prefs = await db.UserPreferences
    .Include(x => x.UserCategory.Select(y => y.Category))
    .Where(x => x.ApplicationUser_Id == userId).SingleOrDefaultAsync();
}

如果偏好設定為非 null,我們使用首選項來塑造 EF 查詢。對於匿名請求,我們只是運行預設查詢。

資料來源

正如前面提到的我們的應用程式從堆疊溢位和 Twitter 提取資料。我們的設計原則之一就是要從多個不同的資料來源和聚合成一個單一的歸一化的來源。這簡化了用戶端和後端之間的互動,因為用戶端不需要知道任何特定的提供程式的資料格式。在後端,我們實現了一個提供程式模型,使得它易於聚合其他來源,而不需要任何更改 Web Api 或用戶端中。提供程式公開一個一致的介面:

interface IProviderAPI
{
   Task<IEnumerable<Conversation>> GetConversationsAsync(
     Provider provider, Category category,
     IEnumerable<Tag> tags, DateTime from, int maxResults, TextWriter logger);
}

堆疊溢位和 Twitter Api 能夠提供足夠的能力,但擁有這種能力來複雜性。我們發現,StacMan 和 LINQtoTwitter NuGet 包作出處理 Api 容易得多。LINQtoTwitter 和 StacMan 是確鑿、 積極支援,開放原始碼,容易使用與 C#。

處理密碼和其他秘密

我們遵循文章,"為將密碼和其他敏感性資料部署到ASP.NET和 Azure 應用程式服務的最佳做法"(bit.ly/1zlNiQI),哪些任務從來沒有檢查原始程式碼中的密碼。我們只有在輔助設定檔在本地開發機器上存儲機密資訊。若要將應用程式部署到 Azure,我們使用 Windows PowerShell 或 Azure 門戶。

這種方法非常適合於 Web 應用程式。我們搬出帶有以下標記的 web.config 檔的秘密:

<appSettings file="..\..\AppSettingsSecrets.config">
</appSettings>

將檔從原始目錄移兩個層面意味著它是完全沒有解決方案目錄並不會添加到原始程式碼管理。

使用一個主控台應用程式 (WebJobs) 的 app.config 檔不支援相對路徑,但是它不支援絕對路徑。你可以使用絕對路徑,將你的秘密移出您的專案目錄。下面的標記中的 C:\secrets\AppSettingsSecrets.config 檔和非敏感性資料在 app.config 檔中的添加的秘密:

<configuration>
  <appSettings file="C:\secrets\AppSettingsSecrets.config">
    <add key="TwitterMaxThreads" value="24" />
    <add key="StackOverflowMaxThreads" value="24" />
    <add key="MaxDaysForPurge" value="30" />
  </appSettings>
</configuration>

處理在我們的 Windows PowerShell 腳本的秘密我們使用出口 CliXml Cmdlet 將加密的機密匯出到磁片和導入 CliXml,以閱讀的秘密。

使一切自動化

DevOps 的最佳做法是使一切自動化。我們原來寫 Windows PowerShell 腳本來創建我們的應用程式要求 (Web 應用程式、 資料庫、 存儲) 的蔚藍資源和鉤上的所有資源,例如,設置連接字串和應用程式設定的秘密。

Visual Studio部署嚮導做得好的自動化部署到 Azure,但仍有幾部手動步驟來部署和配置應用程式:

  • 進入 SQL Azure 資料庫的管理員帳戶的密碼。
  • 輸入的 Web 應用程式和 WebJob 的應用程式設定秘密。
  • 進入 WebJob 存儲帳戶字串掛鉤 WebJob 監測。
  • 更新在 Facebook 和谷歌開發人員主控台,部署 URL,以啟用 OAuth 社會登錄。

新的部署 URL 要求您更新您的 OAuth 提供程式身份驗證 URL,所以沒有辦法自動執行的最後一步,而使用自訂的域的名稱。我們 Windows PowerShell 腳本創建所有蔚藍的資源我們需要和他們掛鉤,所以可以自動化的一切都自動化的。

你部署 WebJobVisual Studio,從第一次提示您設置為運行 WebJob 的排程。(我們運行 WebJob 每三個小時.)在寫這篇文章的時候,還有沒有辦法在 Windows PowerShell 設置 WebJob 排程。之後運行 Windows PowerShell 創建和部署腳本,你需要一次性額外步驟,部署從Visual Studio設置時程表,WebJob 或者你可以設置在門戶上的排程。

我們很快發現,Windows PowerShell 腳本有時會超時試圖創建一個資源時發生。使用傳統的 Azure PowerShell 方式,就沒有簡單的方式來處理隨機資源創建失敗。刪除已成功創建的任何資源需要一個非平凡的腳本,可能可以刪除您不想刪除的資源。甚至當您的腳本是成功的你在完成測試後,您需要刪除所有資源創建的腳本。跟蹤的資源要刪除測試回合後是非平凡且容易出錯。

注意該資源創建超時不是 Azure 中的存在缺陷。遠端創建複雜的資源,如資料伺服器或 Web 應用程式,是本質上耗費時間的。從一開始就處理超時和失敗,必須構建雲應用程式。

蔚藍的資源管理器 (ARM) 的救援

臂使您可以創建資源作為一個群體。這允許您輕鬆地創建您的資源和處理暫態性故障,所以如果您的腳本不能創建一個資源,你可以再試一次。此外,清理是很容易的。您只需刪除您的資源組,和所有依賴的物件被自動刪除。

暫態故障很少發生,並通常只有一個重試操作成功的必要條件。以下代碼片段從 Windows PowerShell 腳本顯示一個簡單的方法來執行重試邏輯與線性退避,當使用 ARM 的範本:

$cnt = 0
$SleepSeconds = 30$ProvisioningState = 'Failed'while ( [string]::Compare($ProvisioningState, 'Failed', $True) -eq 0 -and ($cnt -lt 4 ) ){   My-New-AzureResourceGroup -RGname $RGname `    -WebSiteName $WebSiteName -HostingPlanName $HostingPlanName
  $RGD = Get-AzureResourceGroupDeployment -ResourceGroupName $RGname  $ProvisioningState = $RGD.ProvisioningState  Start-Sleep -s ($SleepSeconds * $cnt)  $cnt++}

我新 AzureResourceGroup 是一個 Windows PowerShell 函數我們寫道,包裝對 Cmdlet 新-AzureResourceGroup,使用 ARM 的範本來創建蔚藍資源的調用。新 AzureResourceGroup 電話幾乎總是會成功,但創建範本所指定的資源可能會超時。

如果不創建任何資源,資源調配的狀態失敗,和腳本會睡著,然後重試。在重試,不是重新創建已成功創建的資源。前面提到的腳本嘗試重試三次。(四行中的失敗幾乎可以肯定表明非瞬態錯誤)。

ARM 提供冪等性是創建許多資源的腳本中非常有用。我們並不建議你需要這種重試邏輯在您的部署,但手臂給你這種選擇時是有益的。 請參閱"使用 Azure PowerShell 與 Azure 資源管理器"(bit.ly/1GyaMzv)。

生成集成和自動化的部署

Visual Studio網上讓它容易地設置持續集成 (CI)。每當代碼簽入Team Foundation伺服器 (TFS),它會自動觸發生成和運行單元測試。我們還採用持續交付 (CD)。如果構建和自動化的單元測試是成功的該應用程式將自動部署到我們蔚藍的試驗場。您可以瞭解如何設置 CI/CD 到 Azure 在文檔頁、"連續交付給蔚藍使用Visual Studio線上"(bit.ly/1OkMkaW)。

早在開發週期,當有三個或更多的人積極檢查在原始程式碼中,我們使用預設組建定義觸發器生成測試部署週期在 3 上午,星期一到星期五的開始。這很好,讓我們所有人都有機會做一個快速測試 Web 網站上的,我們開始每天早上上班的時候。隨著基本代碼穩定,簽了不那麼頻繁,但也許更多是關鍵,我們設置觸發器為 CI 模式,所以每次檢查中會觸發該進程。當我們到了"清理代碼"的階段,與頻繁的低風險的變化,我們將觸發器設置為滾動生成,生成,測試,部署週期觸發時頂多每小時。圖 8 顯示生成摘要,其中包括部署和測試覆蓋。

生成摘要
圖 8 生成摘要

總結

在這篇文章中,我們看的一些注意事項時創建一個雲後端聚合和處理資料,並對移動用戶端服務。我們的應用程式範例沒有個人一塊是極其複雜,但有很多的運動部件,這是典型的基於雲的解決方案。我們還看著Visual Studio線上使一個小團隊來運行連續的生成和連續部署沒有專用 DevOps 經理。

在第 2 部分中,我們會詳細瞭解一下在用戶端應用程式和如何 Xamarin 形式讓它容易地面向多個平臺與最少的特定于平臺的代碼。我們還將深入探討 OAuth2 社會登錄的奧秘。


Rick Anderson 作為一個高級程式設計作家對微軟來說,著重于ASP.NETMVC,微軟 Azure 和Entity Framework的工作。你可以跟隨他在 Twitter 上 twitter.com/RickAndMSFT

Kraig Brockschmidt 作為微軟高級內容開發人員工作,重點是跨平臺的移動應用程式。他是作者的"HTML、 CSS 和 JavaScript 程式設計 Windows 應用商店應用程式"(兩個版本) 從微軟出版社和博客上的 kraigbrockschmidt.com

Tom Dykstra 是在微軟,專注于微軟 Azure 和ASP.NET高級內容開發人員。

Erik Reitan 是在微軟高級內容開發人員。他專注于微軟 Azure 和ASP.NET。 跟著他在 Twitter 上 twitter.com/ReitanErik

Mike Wasson 是在 Microsoft 內容開發人員。多年來,他記錄了 Win32 的多媒體 Api。他目前正在寫關於微軟 Azure 和ASP.NET。

衷心感謝以下技術專家對本文的審閱:Michael科利爾,John德哈威蘭,布萊迪胃、RyanJones、 維賈伊 · 拉瑪克裡斯南普拉 Rastogi