AZURE STORAGE – BLOB’S SDK
MODULE: APPLICATION DEVELOPMENT 3A
CONTENT DEVELOPED BY: CASSIM VANKER
LEARNING OBJECTIVES
• Azure Storage
• Blobs in C#:
• Writing to Blobs in C#
• Create A New Container
• Container Names
• Blob Names
• Upload to a Container
• List blobs in a Container
• Download a Blob
• Delete a Blob
• Handling Optimistic Concurrency in Blobs
WRITING TO BLOBS IN C#
Define a connection string:
<appSettings> <add key="StorageConnectionString"
value="DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key" />
</appSettings>
Reference:
using Microsoft.WindowsAzure; // CloudConfigurationManager
using Microsoft.WindowsAzure.Storage; // CloudStorageAccount
Using Microsoft.WindowsAzure.Storage.Blob; // Blob storage types
Make the connection:
CloudStorageAccount storageAccount =
CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
Create a container service:
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CREATE A NEW CONTAINER
// Retrieve a reference to a container.
CloudBlobContainer container =
blobClient.GetContainerReference("mycontainer");
// Create the container if it doesn't already exist.
container.CreateIfNotExists();
CONTAINER NAMES
• Container names must start with a letter or number, and can contain only
letters, numbers, and the dash (-) character.
• Every dash (-) character must be immediately preceded and followed by a
letter or number; consecutive dashes are not permitted in container names.
• All letters in a container name must be lowercase.
• Container names must be from 3 through 63 characters long.
BLOB NAMES
• A blob name can contain any combination of characters.
• A blob name must be at least one character long and cannot be more than 1,024
characters long.
• Blob names are case-sensitive.
• Reserved URL characters must be properly escaped.
• The number of path segments comprising the blob name cannot exceed 254. A path
segment is the string between consecutive delimiter characters (e.g., the forward slash
'/') that corresponds to the name of a virtual directory.
UPLOAD TO A CONTAINER
// Retrieve reference to a blob named "myblob".
CloudBlockBlob blockBlob = container.GetBlockBlobReference("myblob");
// Create or overwrite the "myblob" blob with contents from a local file.
using (var fileStream = System.IO.File.OpenRead(@"path\myfile")) {
blockBlob.UploadFromStream(fileStream); }
LIST BLOBS IN A CONTAINER
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("photos");
// Loop over items within the container and output the length and URI.
foreach (IListBlobItem item in container.ListBlobs(null, false)) {
if (item.GetType() == typeof(CloudBlockBlob)) {
CloudBlockBlob blob = (CloudBlockBlob)item;
Console.WriteLine("Block blob of length {0}: {1}", blob.Properties.Length, blob.Uri);
}
else if (item.GetType() == typeof(CloudPageBlob)) {
CloudPageBlob pageBlob = (CloudPageBlob)item;
Console.WriteLine("Page blob of length {0}: {1}", pageBlob.Properties.Length, pageBlob.Uri);
} else if (item.GetType() == typeof(CloudBlobDirectory)) {
CloudBlobDirectory directory = (CloudBlobDirectory)item; Console.WriteLine("Directory: {0}", directory.Uri);
}
}
DOWNLOAD A BLOB
// Retrieve reference to a blob named "photo1.jpg".
CloudBlockBlob blockBlob = container.GetBlockBlobReference("photo1.jpg");
// Save blob contents to a file.
using (var fileStream = System.IO.File.OpenWrite(@"path\myfile")) {
blockBlob.DownloadToStream(fileStream);
}
DELETE A BLOB
// Retrieve reference to a previously created container.
CloudBlobContainer container =
blobClient.GetContainerReference("mycontainer");
// Retrieve reference to a blob named "myblob.txt".
CloudBlockBlob blockBlob = container.GetBlockBlobReference("myblob.txt");
// Delete the blob.
blockBlob.Delete();
HANDLING OPTIMISTIC CONCURRENCY IN BLOBS
How to handle concurrency in Blobs:
• Retrieve a blob from the storage service, the response includes an HTTP Etag and the
header value that identifies the current version of the object in the storage service.
• When you update the blob, include the ETag value you received in step 1 in the If-
Match conditional header of the request you send to the service.
• The service compares the ETag value in the request with the current ETag value of the
blob.
• If the current ETag value of the blob is a different version than the ETag the service
returns a 412 error to the client. This indicates to the client that another process has
updated the blob since the client retrieved it.
• If the current ETag value of the blob is the same version as the the service performs
the requested operation and updates the current ETag value of the blob to show that
it has created a new version.
HANDLING OPTIMISTIC CONCURRENCY IN BLOBS
// Retrieve the ETag from the newly created // Now try to update the blob using the orignal
blob ETag provided when the blob was created
try {
string orignalETag = blockBlob.Properties.ETag; blockBlob.UploadText(helloText,accessCondition:
AccessCondition.GenerateIfMatchCondition(orignal
// This code simulates an update by a third ETag));
party. }
catch (StorageException ex) {
string helloText = "Blob updated by a third
if (ex.RequestInformation.HttpStatusCode ==
party."; (int)HttpStatusCode.PreconditionFailed)
// No etag, provided so original blob is {
Console.WriteLine("Precondition failure as
overwritten (thus generating a new etag)
expected. Blob's orignal etag no longer
blockBlob.UploadText(helloText); matches"); // TODO: client can decide on
how it wants to handle the 3rd party
Console.WriteLine("Blob updated. Updated updated content.
ETag = {0}", blockBlob.Properties.ETag); } else throw;
}
HANDLING PESSIMISTIC CONCURRENCY IN BLOBS
// 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 will 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 third party update to blob without lease
try {
// Below operation will fail as no valid lease provided
Console.WriteLine("Trying to update blob without valid lease");
blockBlob.UploadText("Update without lease, will fail"); }
catch (StorageException ex) {
if (ex.RequestInformation.HttpStatusCode == (int)HttpStatusCode.PreconditionFailed) Console.WriteLine("Precondition failure as
expected. Blob's lease does not match"); else throw; }