本文說明使用適用於 .NET 的 Azure Blob 記憶體用戶端連結庫 11.x 版的程式代碼範例。
在 2023 年 3 月 31 日,我們已淘汰不符合目前 Azure SDK 指導方針的 Azure SDK 程式庫支援。 新的 Azure SDK 程式庫會定期更新,以促進一致的體驗並加強您的安全性態勢。 建議您轉換至新的 Azure SDK 程式庫,以利用新功能和重大安全性更新。
雖然較舊的程式庫仍可在 2023 年 3 月 31 日之後使用,但它們將不再收到 Microsoft 的官方支援和更新。 如需詳細資訊,請參閱支援中止公告。
建立快照
若要使用適用於 .NET 的 Azure 儲存體用戶端程式庫 11.x 版建立區塊 Blob 的快照,請使用下列其中一種方法:
下列程式代碼範例示範如何使用 11.x 版建立快照集。 此範例會在建立快照集時指定快照集的其他元數據。
private static async Task CreateBlockBlobSnapshot(CloudBlobContainer container)
{
// Create a new block blob in the container.
CloudBlockBlob baseBlob = container.GetBlockBlobReference("sample-base-blob.txt");
// Add blob metadata.
baseBlob.Metadata.Add("ApproxBlobCreatedDate", DateTime.UtcNow.ToString());
try
{
// Upload the blob to create it, with its metadata.
await baseBlob.UploadTextAsync(string.Format("Base blob: {0}", baseBlob.Uri.ToString()));
// Sleep 5 seconds.
System.Threading.Thread.Sleep(5000);
// Create a snapshot of the base blob.
// You can specify metadata at the time that the snapshot is created.
// If no metadata is specified, then the blob's metadata is copied to the snapshot.
Dictionary<string, string> metadata = new Dictionary<string, string>();
metadata.Add("ApproxSnapshotCreatedDate", DateTime.UtcNow.ToString());
await baseBlob.CreateSnapshotAsync(metadata, null, null, null);
Console.WriteLine(snapshot.SnapshotQualifiedStorageUri.PrimaryUri);
}
catch (StorageException e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
throw;
}
}
刪除快照集
若要使用適用於 .NET 的 Azure 儲存體用戶端程式庫 11.x 版刪除 blob 及其快照,請使用下列其中一種刪除 blob 的方法,並包含 DeleteSnapshotsOption 列舉:
下列程式代碼範例示範如何在 .NET 中刪除 Blob 及其快照集,其中 blockBlob 是類型為 [CloudBlockBlob][dotnet_CloudBlockBlob]的物件:
await blockBlob.DeleteIfExistsAsync(DeleteSnapshotsOption.IncludeSnapshots, null, null, null);
建立預存存取原則
若要在具有適用於 Azure 記憶體之 .NET 用戶端連結庫 11.x 版的容器上建立預存存取原則,請呼叫下列其中一種方法:
下列範例會建立一天的預存存取原則,並授與讀取、寫入和清單許可權:
private static async Task CreateStoredAccessPolicyAsync(CloudBlobContainer container, string policyName)
{
// Create a new stored access policy and define its constraints.
// The access policy provides create, write, read, list, and delete permissions.
SharedAccessBlobPolicy sharedPolicy = new SharedAccessBlobPolicy()
{
// When the start time for the SAS is omitted, the start time is assumed to be the time when Azure Storage receives the request.
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.List |
SharedAccessBlobPermissions.Write
};
// Get the container's existing permissions.
BlobContainerPermissions permissions = await container.GetPermissionsAsync();
// Add the new policy to the container's permissions, and set the container's permissions.
permissions.SharedAccessPolicies.Add(policyName, sharedPolicy);
await container.SetPermissionsAsync(permissions);
}
為 Blob 容器建立服務 SAS
若要建立容器的服務 SAS,請呼叫 CloudBlobContainer.GetSharedAccessSignature 方法。
private static string GetContainerSasUri(CloudBlobContainer container,
string storedPolicyName = null)
{
string sasContainerToken;
// If no stored policy is specified, create a new access policy and define its constraints.
if (storedPolicyName == null)
{
// Note that the SharedAccessBlobPolicy class is used both to define
// the parameters of an ad hoc SAS, and to construct a shared access policy
// that is saved to the container's shared access policies.
SharedAccessBlobPolicy adHocPolicy = new SharedAccessBlobPolicy()
{
// When the start time for the SAS is omitted, the start time is assumed
// to be the time when the storage service receives the request. Omitting
// the start time for a SAS that is effective immediately helps to avoid clock skew.
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.List
};
// Generate the shared access signature on the container,
// setting the constraints directly on the signature.
sasContainerToken = container.GetSharedAccessSignature(adHocPolicy, null);
Console.WriteLine("SAS for blob container (ad hoc): {0}", sasContainerToken);
Console.WriteLine();
}
else
{
// Generate the shared access signature on the container. In this case,
// all of the constraints for the shared access signature are specified
// on the stored access policy, which is provided by name. It is also possible
// to specify some constraints on an ad hoc SAS and others on the stored access policy.
sasContainerToken = container.GetSharedAccessSignature(null, storedPolicyName);
Console.WriteLine("SAS for container (stored access policy): {0}", sasContainerToken);
Console.WriteLine();
}
// Return the URI string for the container, including the SAS token.
return container.Uri + sasContainerToken;
}
建立 Blob 的服務共享存取簽章 (SAS)
若要建立 Blob 的服務 SAS,請呼叫 CloudBlob.GetSharedAccessSignature 方法。
private static string GetBlobSasUri(CloudBlobContainer container,
string blobName,
string policyName = null)
{
string sasBlobToken;
// Get a reference to a blob within the container.
// Note that the blob may not exist yet, but a SAS can still be created for it.
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
if (policyName == null)
{
// Create a new access policy and define its constraints.
// Note that the SharedAccessBlobPolicy class is used both to define the parameters
// of an ad hoc SAS, and to construct a shared access policy that is saved to
// the container's shared access policies.
SharedAccessBlobPolicy adHocSAS = new SharedAccessBlobPolicy()
{
// When the start time for the SAS is omitted, the start time is assumed to be
// the time when the storage service receives the request. Omitting the start time
// for a SAS that is effective immediately helps to avoid clock skew.
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
Permissions = SharedAccessBlobPermissions.Read |
SharedAccessBlobPermissions.Write |
SharedAccessBlobPermissions.Create
};
// Generate the shared access signature on the blob,
// setting the constraints directly on the signature.
sasBlobToken = blob.GetSharedAccessSignature(adHocSAS);
Console.WriteLine("SAS for blob (ad hoc): {0}", sasBlobToken);
Console.WriteLine();
}
else
{
// Generate the shared access signature on the blob. In this case, all of the constraints
// for the SAS are specified on the container's stored access policy.
sasBlobToken = blob.GetSharedAccessSignature(null, policyName);
Console.WriteLine("SAS for blob (stored access policy): {0}", sasBlobToken);
Console.WriteLine();
}
// Return the URI string for the container, including the SAS token.
return blob.Uri + sasBlobToken;
}
建立帳戶 SAS
若要建立容器的帳戶 SAS,請呼叫 CloudStorageAccount.GetSharedAccessSignature 方法。
下列程式碼範例建立一個帳戶 SAS,對 Blob 和檔案服務有效,賦予客戶端讀取、寫入和列出服務層級 API 的許可權。 帳戶 SAS 會將通訊協定限制為 HTTPS,因此必須使用 HTTPS 提出要求。 請記得以您自己的值取代角括號中的預留位置值:
static string GetAccountSASToken()
{
// To create the account SAS, you need to use Shared Key credentials. Modify for your account.
const string ConnectionString = "DefaultEndpointsProtocol=https;AccountName=<storage-account>;AccountKey=<account-key>";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
// Create a new access policy for the account.
SharedAccessAccountPolicy policy = new SharedAccessAccountPolicy()
{
Permissions = SharedAccessAccountPermissions.Read |
SharedAccessAccountPermissions.Write |
SharedAccessAccountPermissions.List,
Services = SharedAccessAccountServices.Blob | SharedAccessAccountServices.File,
ResourceTypes = SharedAccessAccountResourceTypes.Service,
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
Protocols = SharedAccessProtocol.HttpsOnly
};
// Return the SAS token.
return storageAccount.GetSharedAccessSignature(policy);
}
從用戶端使用帳戶 SAS
在此程式碼片段中,以您的儲存帳戶名稱替換 <storage-account> 佔位符。
static void UseAccountSAS(string sasToken)
{
// Create new storage credentials using the SAS token.
StorageCredentials accountSAS = new StorageCredentials(sasToken);
// Use these credentials and the account name to create a Blob service client.
CloudStorageAccount accountWithSAS = new CloudStorageAccount(accountSAS, "<storage-account>", endpointSuffix: null, useHttps: true);
CloudBlobClient blobClientWithSAS = accountWithSAS.CreateCloudBlobClient();
// Now set the service properties for the Blob client created with the SAS.
blobClientWithSAS.SetServiceProperties(new ServiceProperties()
{
HourMetrics = new MetricsProperties()
{
MetricsLevel = MetricsLevel.ServiceAndApi,
RetentionDays = 7,
Version = "1.0"
},
MinuteMetrics = new MetricsProperties()
{
MetricsLevel = MetricsLevel.ServiceAndApi,
RetentionDays = 7,
Version = "1.0"
},
Logging = new LoggingProperties()
{
LoggingOperations = LoggingOperations.All,
RetentionDays = 14,
Version = "1.0"
}
});
// The permissions granted by the account SAS also permit you to retrieve service properties.
ServiceProperties serviceProperties = blobClientWithSAS.GetServiceProperties();
Console.WriteLine(serviceProperties.HourMetrics.MetricsLevel);
Console.WriteLine(serviceProperties.HourMetrics.RetentionDays);
Console.WriteLine(serviceProperties.HourMetrics.Version);
}
Blob 的樂觀並發控制
程式代碼範例:
public void DemonstrateOptimisticConcurrencyBlob(string containerName, string blobName)
{
Console.WriteLine("Demonstrate optimistic concurrency");
// Parse connection string and create container.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
container.CreateIfNotExists();
// Create test blob. The default strategy is last writer wins, so
// write operation will overwrite existing blob if present.
CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
blockBlob.UploadText("Hello World!");
// Retrieve the ETag from the newly created blob.
string originalETag = blockBlob.Properties.ETag;
Console.WriteLine("Blob added. Original ETag = {0}", originalETag);
/// This code simulates an update by another client.
string helloText = "Blob updated by another client.";
// No ETag was provided, so original blob is overwritten and ETag updated.
blockBlob.UploadText(helloText);
Console.WriteLine("Blob updated. Updated ETag = {0}", blockBlob.Properties.ETag);
// Now try to update the blob using the original ETag value.
try
{
Console.WriteLine(@"Attempt to update blob using original ETag
to generate if-match access condition");
blockBlob.UploadText(helloText, accessCondition: AccessCondition.GenerateIfMatchCondition(originalETag));
}
catch (StorageException ex)
{
if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed)
{
Console.WriteLine(@"Precondition failure as expected.
Blob's ETag does not match.");
}
else
{
throw;
}
}
Console.WriteLine();
}
Blob 的悲觀並發控制
程式代碼範例:
public void DemonstratePessimisticConcurrencyBlob(string containerName, string blobName)
{
Console.WriteLine("Demonstrate pessimistic concurrency");
// Parse connection string and create container.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
container.CreateIfNotExists();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName);
blockBlob.UploadText("Hello World!");
Console.WriteLine("Blob added.");
// Acquire lease for 15 seconds.
string lease = blockBlob.AcquireLease(TimeSpan.FromSeconds(15), null);
Console.WriteLine("Blob lease acquired. Lease = {0}", lease);
// Update blob using lease. This operation should succeed.
const string helloText = "Blob updated";
var accessCondition = AccessCondition.GenerateLeaseCondition(lease);
blockBlob.UploadText(helloText, accessCondition: accessCondition);
Console.WriteLine("Blob updated using an exclusive lease");
// Simulate another client attempting to update to blob without providing lease.
try
{
// Operation will fail as no valid lease was provided.
Console.WriteLine("Now try to update blob without valid lease.");
blockBlob.UploadText("Update operation will fail without lease.");
}
catch (StorageException ex)
{
if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed)
{
Console.WriteLine(@"Precondition failure error as expected.
Blob lease not provided.");
}
else
{
throw;
}
}
// Release lease proactively.
blockBlob.ReleaseLease(accessCondition);
Console.WriteLine();
}
使用 Blob 記憶體建置高可用性應用程式
下載 範例專案、解壓縮 storage-dotnet-circuit-breaker-pattern-ha-apps-using-ra-grs.zip 檔案,然後流覽至 v11 資料夾以尋找項目檔。
您也可以使用 git ,將應用程式的複本下載到您的開發環境。 v11資料夾中的範例專案包含主控台應用程式。
git clone https://github.com/Azure-Samples/storage-dotnet-circuit-breaker-pattern-ha-apps-using-ra-grs.git
設置樣本
在應用程式中,您必須提供記憶體帳戶的連接字串。 您可以在執行應用程式的本機電腦上,將此連接字串儲存在環境變數內。 根據您的作業系統,請遵循下列其中一個範例來建立環境變數。
在 Azure 入口網站中,瀏覽至您的儲存體帳戶。 在儲存體帳戶中選取 [設定] 下的 [存取金鑰]。 從主要或次要金鑰複製連接字串。 根據您的作業系統執行以下其中一個命令,將 <yourconnectionstring> 替換為您的實際連接字串。 此命令會將環境變數儲存至本機計算機。 在 Windows 中,您需要重新載入 命令提示字元 或使用的殼層,環境變數才會生效。
執行主控台應用程式
在 Visual Studio 中,按下 F5 或選取 [啟動],開始對應用程式進行偵錯。 如果已設定套件還原,Visual Studio 會自動還原遺漏的 NuGet 套件,請瀏覽 安裝及重新安裝套件的套件還原功能 以深入瞭解。
主控台視窗隨即啟動,應用程式會開始執行。 應用程式會將 HelloWorld.png 映像從解決方案上傳至記憶體帳戶。 應用程式會檢查以確保映像已復寫至次要 RA-GZRS 端點。 然後,它會開始下載映射最多 999 次。 每個讀取都會以 P 或 S 表示。其中 P 代表主要端點, 而 S 代表次要端點。
在範例程式代碼中, RunCircuitBreakerAsync 檔案中 Program.cs 的工作是用來使用 DownloadToFileAsync 方法從記憶體帳戶下載映像。 下載之前,會定義 OperationContext 。 操作情境定義了當下載成功完成時觸發的事件處理程式,或者當下載失敗並正在重試時觸發的事件處理程式。
了解範例程式碼
重試事件處理程式
下載 OperationContextRetrying 映射失敗並設定為重試時,會呼叫事件處理程式。 如果達到應用程式中定義的重試次數上限,要求的 LocationMode 會變更為 SecondaryOnly。 此設定會強制應用程式嘗試從次要端點下載映像。 此設定可減少要求映像所需的時間,因為主要端點不會無限期重試。
private static void OperationContextRetrying(object sender, RequestEventArgs e)
{
retryCount++;
Console.WriteLine("Retrying event because of failure reading the primary. RetryCount = " + retryCount);
// Check if we have had more than n retries in which case switch to secondary.
if (retryCount >= retryThreshold)
{
// Check to see if we can fail over to secondary.
if (blobClient.DefaultRequestOptions.LocationMode != LocationMode.SecondaryOnly)
{
blobClient.DefaultRequestOptions.LocationMode = LocationMode.SecondaryOnly;
retryCount = 0;
}
else
{
throw new ApplicationException("Both primary and secondary are unreachable. Check your application's network connection. ");
}
}
}
要求已完成事件處理程式
OperationContextRequestCompleted成功下載映射時,會呼叫事件處理程式。 如果應用程式使用次要端點,應用程式會繼續使用此端點最多 20 次。 20 次之後,應用程式會將 LocationMode 設定回 PrimaryThenSecondary ,並重試主要端點。 如果要求成功,應用程式會繼續從主要端點讀取。
private static void OperationContextRequestCompleted(object sender, RequestEventArgs e)
{
if (blobClient.DefaultRequestOptions.LocationMode == LocationMode.SecondaryOnly)
{
// You're reading the secondary. Let it read the secondary [secondaryThreshold] times,
// then switch back to the primary and see if it's available now.
secondaryReadCount++;
if (secondaryReadCount >= secondaryThreshold)
{
blobClient.DefaultRequestOptions.LocationMode = LocationMode.PrimaryThenSecondary;
secondaryReadCount = 0;
}
}
}
將大量隨機數據上傳至 Azure 記憶體
線程數目下限和上限設定為 100,以確保允許大量的並行連線。
private static async Task UploadFilesAsync()
{
// Create five randomly named containers to store the uploaded files.
CloudBlobContainer[] containers = await GetRandomContainersAsync();
var currentdir = System.IO.Directory.GetCurrentDirectory();
// Path to the directory to upload
string uploadPath = currentdir + "\\upload";
// Start a timer to measure how long it takes to upload all the files.
Stopwatch time = Stopwatch.StartNew();
try
{
Console.WriteLine("Iterating in directory: {0}", uploadPath);
int count = 0;
int max_outstanding = 100;
int completed_count = 0;
// Define the BlobRequestOptions on the upload.
// This includes defining an exponential retry policy to ensure that failed connections
// are retried with a back off policy. As multiple large files are being uploaded using
// large block sizes, this can cause an issue if an exponential retry policy is not defined.
// Additionally, parallel operations are enabled with a thread count of 8.
// This should be a multiple of the number of processor cores in the machine.
// Lastly, MD5 hash validation is disabled for this example, improving the upload speed.
BlobRequestOptions options = new BlobRequestOptions
{
ParallelOperationThreadCount = 8,
DisableContentMD5Validation = true,
StoreBlobContentMD5 = false
};
// Create a new instance of the SemaphoreSlim class to
// define the number of threads to use in the application.
SemaphoreSlim sem = new SemaphoreSlim(max_outstanding, max_outstanding);
List<Task> tasks = new List<Task>();
Console.WriteLine("Found {0} file(s)", Directory.GetFiles(uploadPath).Count());
// Iterate through the files
foreach (string path in Directory.GetFiles(uploadPath))
{
var container = containers[count % 5];
string fileName = Path.GetFileName(path);
Console.WriteLine("Uploading {0} to container {1}", path, container.Name);
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
// Set the block size to 100MB.
blockBlob.StreamWriteSizeInBytes = 100 * 1024 * 1024;
await sem.WaitAsync();
// Create a task for each file to upload. The tasks are
// added to a collection and all run asynchronously.
tasks.Add(blockBlob.UploadFromFileAsync(path, null, options, null).ContinueWith((t) =>
{
sem.Release();
Interlocked.Increment(ref completed_count);
}));
count++;
}
// Run all the tasks asynchronously.
await Task.WhenAll(tasks);
time.Stop();
Console.WriteLine("Upload has been completed in {0} seconds. Press any key to continue", time.Elapsed.TotalSeconds.ToString());
Console.ReadLine();
}
catch (DirectoryNotFoundException ex)
{
Console.WriteLine("Error parsing files in the directory: {0}", ex.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
除了設定線程和連線限制設定之外,UploadFromStreamAsync 方法的 BlobRequestOptions 也會設定為使用平行處理原則並停用 MD5 哈希驗證。 檔案會以 100 MB 區塊上傳,此設定可提供更佳的效能,但如果使用效能不佳的網路,就好像重試整個 100 MB 區塊失敗一樣,可能會耗費成本。
| 財產 | 價值 | 說明 |
|---|---|---|
| 平行操作執行緒計數 | 8 | 此設定會在上傳時將 Blob 分成區塊。 為了達到最高效能,此值應該是核心數目的八倍。 |
| 停用內容MD5驗證 | 是 | 這個屬性會停用檢查已上傳內容的 MD5 哈希。 停用 MD5 驗證會產生更快的傳輸。 但不會確認正在傳輸之檔案的有效性或完整性。 |
| StoreBlobContentMD5 | 假的 | 這個屬性會判斷 MD5 哈希是否計算並儲存在檔案中。 |
| RetryPolicy | 2 秒的退避,最多重試 10 次 | 決定要求的重試策略。 在此範例中,對於連線失敗會進行重試,指數重試 原則設定為 2 秒延遲,並且最大重試次數為 10 次。 當您的應用程式接近達到 Blob 記憶體的延展性目標時,此設定很重要。 如需詳細資訊,請參閱 Blob 儲存體的延展性和效能目標。 |
從 Azure 儲存體下載大量隨機資料
應用程式會讀取位於 storageconnectionstring 中所指定記憶體帳戶中的容器。 在容器中使用 ListBlobsSegmentedAsync 方法每次循環遍歷 10 個 Blob,並使用 DownloadToFileAsync 方法將它們下載到本機電腦。
下表顯示為每個 Blob 在下載時定義的 BlobRequestOptions。
| 財產 | 價值 | 說明 |
|---|---|---|
| 停用內容MD5驗證 | 是 | 這個屬性會停用檢查已上傳內容的 MD5 哈希。 停用 MD5 驗證會產生更快的傳輸。 但不會確認正在傳輸之檔案的有效性或完整性。 |
| StoreBlobContentMD5 | 假的 | 這個屬性會判斷 MD5 哈希是否計算並儲存。 |
private static async Task DownloadFilesAsync()
{
CloudBlobClient blobClient = GetCloudBlobClient();
// Define the BlobRequestOptions on the download, including disabling MD5
// hash validation for this example, this improves the download speed.
BlobRequestOptions options = new BlobRequestOptions
{
DisableContentMD5Validation = true,
StoreBlobContentMD5 = false
};
// Retrieve the list of containers in the storage account.
// Create a directory and configure variables for use later.
BlobContinuationToken continuationToken = null;
List<CloudBlobContainer> containers = new List<CloudBlobContainer>();
do
{
var listingResult = await blobClient.ListContainersSegmentedAsync(continuationToken);
continuationToken = listingResult.ContinuationToken;
containers.AddRange(listingResult.Results);
}
while (continuationToken != null);
var directory = Directory.CreateDirectory("download");
BlobResultSegment resultSegment = null;
Stopwatch time = Stopwatch.StartNew();
// Download the blobs
try
{
List<Task> tasks = new List<Task>();
int max_outstanding = 100;
int completed_count = 0;
// Create a new instance of the SemaphoreSlim class to
// define the number of threads to use in the application.
SemaphoreSlim sem = new SemaphoreSlim(max_outstanding, max_outstanding);
// Iterate through the containers
foreach (CloudBlobContainer container in containers)
{
do
{
// Return the blobs from the container, 10 at a time.
resultSegment = await container.ListBlobsSegmentedAsync(null, true, BlobListingDetails.All, 10, continuationToken, null, null);
continuationToken = resultSegment.ContinuationToken;
{
foreach (var blobItem in resultSegment.Results)
{
if (((CloudBlob)blobItem).Properties.BlobType == BlobType.BlockBlob)
{
// Get the blob and add a task to download the blob asynchronously from the storage account.
CloudBlockBlob blockBlob = container.GetBlockBlobReference(((CloudBlockBlob)blobItem).Name);
Console.WriteLine("Downloading {0} from container {1}", blockBlob.Name, container.Name);
await sem.WaitAsync();
tasks.Add(blockBlob.DownloadToFileAsync(directory.FullName + "\\" + blockBlob.Name, FileMode.Create, null, options, null).ContinueWith((t) =>
{
sem.Release();
Interlocked.Increment(ref completed_count);
}));
}
}
}
}
while (continuationToken != null);
}
// Creates an asynchronous task that completes when all the downloads complete.
await Task.WhenAll(tasks);
}
catch (Exception e)
{
Console.WriteLine("\nError encountered during transfer: {0}", e.Message);
}
time.Stop();
Console.WriteLine("Download has been completed in {0} seconds. Press any key to continue", time.Elapsed.TotalSeconds.ToString());
Console.ReadLine();
}
啟用 Azure 記憶體分析記錄 (傳統)
程式代碼範例:
var storageAccount = CloudStorageAccount.Parse(connStr);
var queueClient = storageAccount.CreateCloudQueueClient();
var serviceProperties = queueClient.GetServiceProperties();
serviceProperties.Logging.LoggingOperations = LoggingOperations.All;
serviceProperties.Logging.RetentionDays = 2;
queueClient.SetServiceProperties(serviceProperties);
修改記錄資料保留期間
下列範例會將 Blob 和 Queue 儲存服務的保留期間輸出到控制台。
var storageAccount = CloudStorageAccount.Parse(connectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
var queueClient = storageAccount.CreateCloudQueueClient();
var blobserviceProperties = blobClient.GetServiceProperties();
var queueserviceProperties = queueClient.GetServiceProperties();
Console.WriteLine("Retention period for logs from the blob service is: " +
blobserviceProperties.Logging.RetentionDays.ToString());
Console.WriteLine("Retention period for logs from the queue service is: " +
queueserviceProperties.Logging.RetentionDays.ToString());
下列範例會將 Blob 和佇列記憶體服務的記錄保留期間變更為 4 天。
blobserviceProperties.Logging.RetentionDays = 4;
queueserviceProperties.Logging.RetentionDays = 4;
blobClient.SetServiceProperties(blobserviceProperties);
queueClient.SetServiceProperties(queueserviceProperties);
啟用 Azure 記憶體分析計量 (傳統)
程式代碼範例:
var storageAccount = CloudStorageAccount.Parse(connStr);
var queueClient = storageAccount.CreateCloudQueueClient();
var serviceProperties = queueClient.GetServiceProperties();
serviceProperties.HourMetrics.MetricsLevel = MetricsLevel.Service;
serviceProperties.HourMetrics.RetentionDays = 10;
queueClient.SetServiceProperties(serviceProperties);
設定用戶端應用程式的傳輸層安全性 (TLS)
下列範例示範如何使用 Azure 記憶體用戶端連結庫 11.x 版,在 .NET 用戶端中啟用 TLS 1.2:
static void EnableTls12()
{
// Enable TLS 1.2 before connecting to Azure Storage
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
// Add your connection string here.
string connectionString = "";
// Connect to Azure Storage and create a new container.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("sample-container");
container.CreateIfNotExists();
}
Microsoft Azure 記憶體監視、診斷和疑難解答 (傳統)
如果儲存體用戶端程式庫在客戶端擲回 StorageException,則 RequestInformation 屬性包含一個包含 ServiceRequestID 屬性的 RequestResult 物件。 您也可以從 OperationContext 實例存取 RequestResult 物件。
下列程式代碼範例示範如何將 OperationContext 物件附加至對儲存服務的請求中,以設定自定義 ClientRequestId 值。 它也會示範如何從回應消息擷取 ServerRequestId 值。
//Parse the connection string for the storage account.
const string ConnectionString = "DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Create an Operation Context that includes custom ClientRequestId string based on constants defined within the application along with a Guid.
OperationContext oc = new OperationContext();
oc.ClientRequestID = String.Format("{0} {1} {2} {3}", HOSTNAME, APPNAME, USERID, Guid.NewGuid().ToString());
try
{
CloudBlobContainer container = blobClient.GetContainerReference("democontainer");
ICloudBlob blob = container.GetBlobReferenceFromServer("testImage.jpg", null, null, oc);
var downloadToPath = string.Format("./{0}", blob.Name);
using (var fs = File.OpenWrite(downloadToPath))
{
blob.DownloadToStream(fs, null, null, oc);
Console.WriteLine("\t Blob downloaded to file: {0}", downloadToPath);
}
}
catch (StorageException storageException)
{
Console.WriteLine("Storage exception {0} occurred", storageException.Message);
// Multiple results may exist due to client side retry logic - each retried operation will have a unique ServiceRequestId
foreach (var result in oc.RequestResults)
{
Console.WriteLine("HttpStatus: {0}, ServiceRequestId {1}", result.HttpStatusCode, result.ServiceRequestID);
}
}
調查用戶端效能問題 - 停用 Nagle 演算法
程式代碼範例:
var storageAccount = CloudStorageAccount.Parse(connStr);
ServicePoint queueServicePoint = ServicePointManager.FindServicePoint(storageAccount.QueueEndpoint);
queueServicePoint.UseNagleAlgorithm = false;
調查網路等待時間問題 - 設定跨原始來源資源分享 (CORS)
程式代碼範例:
CloudBlobClient client = new CloudBlobClient(blobEndpoint, new StorageCredentials(accountName, accountKey));
// Set the service properties.
ServiceProperties sp = client.GetServiceProperties();
sp.DefaultServiceVersion = "2013-08-15";
CorsRule cr = new CorsRule();
cr.AllowedHeaders.Add("*");
cr.AllowedMethods = CorsHttpMethods.Get | CorsHttpMethods.Put;
cr.AllowedOrigins.Add("http://www.contoso.com");
cr.ExposedHeaders.Add("x-ms-*");
cr.MaxAgeInSeconds = 5;
sp.Cors.CorsRules.Clear();
sp.Cors.CorsRules.Add(cr);
client.SetServiceProperties(sp);
建立指定大小的空頁 Blob
為了建立分頁 Blob,我們會先建立 CloudBlobClient 物件,並使用基底 URI 來存取記憶體帳戶的 Blob 記憶體(圖 1 中的 pbaccount ),以及 StorageCredentialsAccountAndKey 物件,如下列範例所示。 接著,此範例會示範如何創建 CloudBlobContainer 物件的參考,並在容器(testvhds)尚未存在時創建該容器。 然後使用 CloudBlobContainer 物件,藉由指定要存取的分頁 Blob 名稱 (os4.vhd) 來建立 CloudPageBlob 物件的參考。 若要建立分頁 Blob,請呼叫 CloudPageBlob.Create,傳入要建立的 Blob 大小上限。 blobSize 必須是 512 個字節的倍數。
using Microsoft.Azure;
using Microsoft.Azure.Storage;
using Microsoft.Azure.Storage.Blob;
long OneGigabyteAsBytes = 1024 * 1024 * 1024;
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve a reference to a container.
CloudBlobContainer container = blobClient.GetContainerReference("testvhds");
// Create the container if it doesn't already exist.
container.CreateIfNotExists();
CloudPageBlob pageBlob = container.GetPageBlobReference("os4.vhd");
pageBlob.Create(16 * OneGigabyteAsBytes);
調整頁面 Blob 大小
若要在建立之後重新調整分頁 Blob 的大小,請使用調整大小方法。 要求的大小應該是 512 位元組的倍數。
pageBlob.Resize(32 * OneGigabyteAsBytes);
將頁面寫入頁 Blob
若要寫入頁面,請使用 CloudPageBlob.WritePages 方法。
pageBlob.WritePages(dataStream, startingOffset);
從頁面 Blob 讀取頁面
若要讀取頁面,請使用 CloudPageBlob.DownloadRangeToByteArray 方法來讀取分頁 Blob 中的位元組範圍。
byte[] buffer = new byte[rangeSize];
pageBlob.DownloadRangeToByteArray(buffer, bufferOffset, pageBlobOffset, rangeSize);
若要判斷哪些頁面受數據支援,請使用 CloudPageBlob.GetPageRanges。 然後,您可以對傳回的範圍進行列舉,並下載每個範圍中的資料。
IEnumerable<PageRange> pageRanges = pageBlob.GetPageRanges();
foreach (PageRange range in pageRanges)
{
// Calculate the range size
int rangeSize = (int)(range.EndOffset + 1 - range.StartOffset);
byte[] buffer = new byte[rangeSize];
// Read from the correct starting offset in the page blob and
// place the data in the bufferOffset of the buffer byte array
pageBlob.DownloadRangeToByteArray(buffer, bufferOffset, range.StartOffset, rangeSize);
// Then use the buffer for the page range just read
}