共用方式為


使用 Azure) 建置Real-World雲端應用程式的非結構化 Blob 儲存體 (

作者 :Rick AndersonTom Dykstra

下載修正專案下載電子書

使用 Azure 電子書建置真實世界雲端應用程式是以 Scott Guthrie 開發的簡報為基礎。 其說明 13 種模式和做法,可協助您成功開發雲端的 Web 應用程式。 如需電子書的相關資訊,請參閱 第一章

在上一章中,我們探討資料分割配置,並說明修正 It 應用程式如何將映射儲存在 Azure 儲存體 Blob 服務中,以及Azure SQL資料庫中的其他工作資料。 在本章中,我們會深入探討 Blob 服務,並示範如何在修正 It 專案程式碼中實作它。

什麼是 Blob 儲存體?

Azure 儲存體 Blob 服務會提供在雲端儲存檔案的方式。 與本機網路檔案系統相比,Blob 服務有許多優點:

  • 其可高度擴充。 單一儲存體帳戶可以儲存 數百 TB,而且您可以有多個儲存體帳戶。 其中一些最大的 Azure 客戶會儲存數百 PB。 Microsoft SkyDrive 使用 Blob 儲存體。
  • 它是永久性的。 您儲存在 Blob 服務中的每個檔案都會自動備份。
  • 它提供高可用性。 儲存體 SLA承諾 99.9% 或 99.99% 執行時間,視您選擇的異地備援選項而定。
  • 它是 Azure 的平臺即服務 (PaaS) 功能,這表示您只是儲存和擷取檔案,只支付您使用的實際儲存體量,而 Azure 會自動負責設定和管理服務所需的所有 VM 和磁片磁碟機。
  • 您可以使用 REST API 或使用程式設計語言 API 來存取 Blob 服務。 SDK 適用于 .NET、JAVA、Ruby 等。
  • 當您將檔案儲存在 Blob 服務中時,可以輕鬆地透過網際網路公開提供檔案。
  • 您可以保護 Blob 服務中的檔案,使其只能由授權的使用者存取,或者您可以提供暫時存取權杖,讓其他人只能使用一段有限的時間。

每當您建置適用于 Azure 的應用程式,而且想要儲存在內部部署環境中的大量資料會進入檔案中,例如影像、影片、PDF、試算表等。-- 請考慮 Blob 服務。

建立儲存體帳戶

若要開始使用 Blob 服務,請在 Azure 中建立儲存體帳戶。 在入口網站中,按一下 [新增 -- 資料服務 -- 儲存體 -- 快速建立],然後輸入 URL 和資料中心位置。 資料中心位置應該與您的 Web 應用程式相同。

建立儲存體 acct

您挑選要儲存內容的主要區域,如果您選擇 異地複 寫選項,Azure 會在國家/地區的另一個部分,在不同的資料中心建立所有資料的複本。 例如,如果您選擇美國西部資料中心,當您將檔案儲存到美國西部資料中心時,但在背景 Azure 中也會將其複製到另一個美國資料中心。 如果災害發生在國家/地區的其中一個部分,您的資料仍然安全。

Azure 不會跨地理政治界限複寫資料:如果您的主要位置位於美國,則您的檔案只會複寫到美國中的其他區域;如果您的主要位置是澳大利亞,則您的檔案只會複寫到澳大利亞的另一個資料中心。

當然,您也可以從腳本執行命令來建立儲存體帳戶,如我們稍早所見。 以下是用來建立儲存體帳戶的Windows PowerShell命令:

# Create a new storage account
New-AzureStorageAccount -StorageAccountName $Name -Location $Location -Verbose

一旦您擁有儲存體帳戶,您就可以立即開始將檔案儲存在 Blob 服務中。

在修正 It 應用程式中使用 Blob 儲存體

[修正] 應用程式可讓您上傳相片。

建立修正它工作

當您按一下 [建立 FixIt]時,應用程式會上傳指定的影像檔案,並將其儲存在 Blob 服務中。

設定 Blob 容器

若要將檔案儲存在 Blob 服務中,您需要 容器 才能將其儲存在其中。 Blob 服務容器會對應至檔系統資料夾。 我們在 [自動化所有專案] 一章 中檢閱的環境建立腳本會建立儲存體帳戶,但不會建立容器。 因此,類別的 PhotoService 方法的目的是 CreateAndConfigure 在容器不存在時建立容器。 這個方法是從 Application_StartGlobal.asax中的 方法呼叫。

public async void CreateAndConfigureAsync()
{
    try
    {
        CloudStorageAccount storageAccount = StorageUtils.StorageAccount;

        // Create a blob client and retrieve reference to images container
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("images");

        // Create the "images" container if it doesn't already exist.
        if (await container.CreateIfNotExistsAsync())
        {
            // Enable public access on the newly created "images" container
            await container.SetPermissionsAsync(
                new BlobContainerPermissions
                {
                    PublicAccess =
                        BlobContainerPublicAccessType.Blob
                });

            log.Information("Successfully created Blob Storage Images Container and made it public");
        }
    }
    catch (Exception ex)
    {
        log.Error(ex, "Failure to Create or Configure images container in Blob Storage Service");
    }
}

儲存體帳戶名稱和存取金鑰會儲存在 appSettingsWeb.config 檔案的集合中,而 方法中的 StorageUtils.StorageAccount 程式碼會使用這些值來建置連接字串並建立連線:

string account = CloudConfigurationManager.GetSetting("StorageAccountName");
string key = CloudConfigurationManager.GetSetting("StorageAccountAccessKey");
string connectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", account, key);
return CloudStorageAccount.Parse(connectionString);

CreateAndConfigureAsync方法接著會建立代表 Blob 服務的 物件,以及代表 Blob 服務中名為 「images」 之容器 (資料夾) 的物件:

CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("images");

如果名為 「images」 的容器尚未存在,則第一次對新的儲存體帳戶執行應用程式時,將會是 true -- 程式碼會建立容器,並設定將它設為公用的許可權。 (根據預設,新的 Blob 容器是私人的,而且只能供有權存取儲存體帳戶的使用者存取。)

if (await container.CreateIfNotExistsAsync())
{
    // Enable public access on the newly created "images" container
    await container.SetPermissionsAsync(
        new BlobContainerPermissions
        {
            PublicAccess =
                BlobContainerPublicAccessType.Blob
        });

    log.Information("Successfully created Blob Storage Images Container and made it public");
}

將上傳的相片儲存在 Blob 儲存體中

若要上傳並儲存影像檔案,應用程式會使用 IPhotoService 類別中介面和 介面的實作 PhotoServicePhotoService.cs檔案包含修正 It 應用程式中與 Blob 服務通訊的所有程式碼。

當使用者按一下 [建立 FixIt] 時,會呼叫下列 MVC 控制器方法。 在此程式碼中, photoService 參考 類別的 PhotoService 實例,並 fixittask 參考實體類別的 FixItTask 實例,該實例會儲存新工作的資料。

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create([Bind(Include = "FixItTaskId,CreatedBy,Owner,Title,Notes,PhotoUrl,IsDone")]FixItTask fixittask, HttpPostedFileBase photo)
{
    if (ModelState.IsValid)
    {
        fixittask.CreatedBy = User.Identity.Name;
        fixittask.PhotoUrl = await photoService.UploadPhotoAsync(photo);
        await fixItRepository.CreateAsync(fixittask);
        return RedirectToAction("Success");
    }

    return View(fixittask);
}

類別 UploadPhotoAsync 中的 PhotoService 方法會將上傳的檔案儲存在 Blob 服務中,並傳回指向新 Blob 的 URL。

public async Task<string> UploadPhotoAsync(HttpPostedFileBase photoToUpload)
{            
    if (photoToUpload == null || photoToUpload.ContentLength == 0)
    {
        return null;
    }

    string fullPath = null;
    Stopwatch timespan = Stopwatch.StartNew();

    try
    {
        CloudStorageAccount storageAccount = StorageUtils.StorageAccount;

        // Create the blob client and reference the container
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer container = blobClient.GetContainerReference("images");

        // Create a unique name for the images we are about to upload
        string imageName = String.Format("task-photo-{0}{1}",
            Guid.NewGuid().ToString(),
            Path.GetExtension(photoToUpload.FileName));

        // Upload image to Blob Storage
        CloudBlockBlob blockBlob = container.GetBlockBlobReference(imageName);
        blockBlob.Properties.ContentType = photoToUpload.ContentType;
        await blockBlob.UploadFromStreamAsync(photoToUpload.InputStream);

        // Convert to be HTTP based URI (default storage path is HTTPS)
        var uriBuilder = new UriBuilder(blockBlob.Uri);
        uriBuilder.Scheme = "http";
        fullPath = uriBuilder.ToString();

        timespan.Stop();
        log.TraceApi("Blob Service", "PhotoService.UploadPhoto", timespan.Elapsed, "imagepath={0}", fullPath);
    }
    catch (Exception ex)
    {
        log.Error(ex, "Error upload photo blob to storage");
    }

    return fullPath;
}

如同 在 方法中 CreateAndConfigure ,程式碼會連線到儲存體帳戶,並建立代表「映射」Blob 容器的物件,但此處假設容器已經存在。

然後它會建立即將上傳之映射的唯一識別碼,方法是將新的 GUID 值與副檔名串連:

string imageName = String.Format("task-photo-{0}{1}",
    Guid.NewGuid().ToString(),
    Path.GetExtension(photoToUpload.FileName));

程式碼接著會使用 Blob 容器物件和新的唯一識別碼來建立 Blob 物件、在該物件上設定屬性,指出它所在的檔案類型,然後使用 Blob 物件將檔案儲存在 Blob 儲存體中。

CloudBlockBlob blockBlob = container.GetBlockBlobReference(imageName);
blockBlob.Properties.ContentType = photoToUpload.ContentType;
blockBlob.UploadFromStream(photoToUpload.InputStream);

最後,它會取得參考 Blob 的 URL。 此 URL 會儲存在資料庫中,並可用於修正它網頁以顯示上傳的影像。

fullPath = String.Format("http://{0}{1}", blockBlob.Uri.DnsSafeHost, blockBlob.Uri.AbsolutePath);

此 URL 會儲存在資料庫中,作為 FixItTask 資料表的其中一個資料行。

public class FixItTask
{
    public int FixItTaskId  { get; set; }
    public string CreatedBy { get; set; }
    [Required]
    public string Owner     { get; set; }
    [Required]
    public string Title     { get; set; }
    public string Notes     { get; set; }
    public string PhotoUrl  { get; set; }
    public bool IsDone      { get; set; } 
}

只有資料庫中的 URL 和 Blob 儲存體中的影像,[修正] 應用程式會將資料庫維持在小型、可調整且成本較低的情況下,而映射則儲存在儲存體便宜且能夠處理數 TB 或 PB 的位置。 一個儲存體帳戶可以儲存數百 TB 的修正相片,而您只需要支付您所使用的費用。 因此,您可以針對第一 GB 從小付費 9 分開始,並針對每個額外 GB 的單位新增更多影像。

顯示上傳的檔案

[修正] 應用程式會在顯示工作的詳細資料時,顯示上傳的影像檔。

使用相片修正 It 工作詳細資料

若要顯示影像,所有 MVC 檢視必須包含 PhotoUrl 傳送至瀏覽器的 HTML 中的值。 Web 服務器和資料庫不會使用迴圈來顯示影像,它們只會提供幾個位元組給影像 URL。 在下列 Razor 程式碼中, Model 參考實體類別的 FixItTask 實例。

<fieldset>
<legend>@Html.DisplayFor(model => model.Title)</legend>
<dl>
    <dt>Opened By</dt>
    <dd>@Html.DisplayFor(model => model.CreatedBy)</dd>
                <br />
    <dt>@Html.DisplayNameFor(model => model.Notes)</dt>
    <dd>@Html.DisplayFor(model => model.Notes)</dd>
                <br />
                @if(Model.PhotoUrl != null) {
        <dd><img src="@Model.PhotoUrl" title="@Model.Title" /></dd>
                }
</dl>
</fieldset>

如果您查看所顯示頁面的 HTML,您會看到指向 Blob 儲存體中影像的 URL,如下所示:

<fieldset>
<legend>Brush the dog again</legend>
<dl>
    <dt>Opened By</dt>
    <dd>Tom</dd>
                <br />
    <dt>Notes</dt>
    <dd>Another dog brushing task</dd>
                <br />
    <dd>
<img src="http://storageaccountname.blob.core.windows.net/images/task-photo-312dd635-ba87-4542-8b15-767032c55f4e.jpg" 
           title="Brush the dog again" />
    </dd>
</dl>
</fieldset>

摘要

您已瞭解修正 It 應用程式如何將映射儲存在 Blob 服務中,以及只儲存 SQL 資料庫中的映射 URL。 使用 Blob 服務可讓 SQL 資料庫比它小很多,因此可以相應增加至幾乎無限制的工作數目,而且不需要撰寫許多程式碼即可完成。

儲存體帳戶中可以有數百 TB 的儲存體成本,而儲存體成本比SQL Database儲存體成本低很多,從每月大約 3 分之 3 分開始加上小型交易費用。 請記住,您不需支付容量上限,但只支付您實際儲存的數量,因此您的應用程式已準備好調整規模,但您不需要支付所有額外的容量。

在下 一章 中,我們將討論讓雲端應用程式能夠正常處理失敗的重要性。

資源

如需詳細資訊,請參閱下列資源:

  • 如何在 .NET 中使用Azure Blob 儲存體服務。 MicrosoftAzure.com 網站上的官方檔。 Blob 儲存體的簡介,後面接著示範如何連線至 Blob 儲存體、建立容器、上傳和下載 Blob 等程式碼範例。
  • FailSafe:建置可調整、復原雲端服務。 Ulrich Homann、Marc Mercuri 和 Mark Simms 的九部分影片系列。 以非常無障礙且有趣的方式呈現高階概念和架構原則,其中包含來自 Microsoft Customer Advisory Team (CAT) 實際客戶經驗的故事。 如需 Azure 儲存體服務和 Blob 的討論,請參閱從 35:13 開始的第 5 集。
  • Microsoft 模式和做法 - Azure 指引。 請參閱代管機密鑰模式。