Azure is my cloud of choice. Not only because you get free stuff, yes you do, but also because of the flexibility and ease of interacting with it. If you don’t have an Azure account, you can register for free here.
One of the features offered by Azure is Storage. There are 3 types of Storage:
- Blobs: used to store files, images, binary data, or video
- Drives: which can be mount on VMs etc like an external drive but virtual
- Tables: scalable structured storage which acts like a database table but with slightly different behaviour and structured.
You can read more on the different types of storage at this CodeProject post.
Azure storage gives you great flexibility for storing data if you are developing an application/website for the cloud. You are not limited to using SQL Server or the also excellent Azure SQL Service. You can mix and match based on whatever it easier and more appropriate for your needs, not to mention that you can seriously save on costs.
25GB of data will set you back £0.39 p/m and 1M transactions against that storage account at £0.04 p/m!!
What makes things even better is the brilliant SDK, tools and documentation provided by Microsoft to facilitate the development of cloud-based applications. Since my current project uses a number of Azure features, I thought I would write a few helpful bits on how to work with blobs in .NET.
Create a container for your blobs###
I’m not going to go through the process of creating a storage account as Microsoft has an excellent guide with pretty pictures to guide you through this here. So, assuming you have your storage account in place and set up your development environment, let’s go and create a container for your blobs. Think of a container as your root virtual directory (C:\MyDirectory) in the cloud. You can create one in only a few lines:
using System.Configuration;
...
// Get the connection string to the storage account from web/app.config
var storageAccount = CloudStorageAccount.Parse(
ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
// Create the blob client.
var blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve a reference to a container.
var container = blobClient.GetContainerReference("anynameyou want");
// Create the container if it doesn't already exist.
container.CreateIfNotExists();
// set access to public (only if you need to)
container.SetPermissions(
new BlobContainerPermissions { PublicAccess =
BlobContainerPublicAccessType.Blob });
Note 1: If you plan on using your storage account for storing images, documents etc that will be used directly by your application, you will need to set the access to public. Otherwise, you will not be able to use the blob url to directly browse your objects. This includes both the live and development environments
Note 2: Your container name need to adhere to certain rules:
- 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.
If the name doesn’t match these rules, you will get a 400 error (bad request)
Note 3: blob naming is a bit more relaxed but you should ensure that URL characters are escaped and avoid terminating blob names with a dot (.) or a forward slash (/)
Create a blob###
Again, the SDK really shines when it comes to uploading data to your blob. There are 4 methods you can use:
- UploadByteArray()
- UploadFile()
- UploadFromStream()
- UploadText()
You can get more information on the available methods and required parameters here.
Let’s see a quick example using the UploadText(string fullFileNamePath)
var storageAccount = CloudStorageAccount.Parse(
ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
// Create the blob client.
var blobClient = storageAccount.CreateCloudBlobClient();
// Get a reference to a container, which may or may not exist.
var container = blobClient.GetContainerReference("nameofyourcontainer");
// Create a new container, if it does not exist
container.CreateIfNotExist();
// Get a reference to a blob, which may or may not exist.
var blob = container.GetBlobReference("testfile.txt");
// Upload content to the blob, which will create the blob if it does not already exist.
blob.UploadFile(@"c:\temp\testfile.txt");
Note: Although containers have a flat structure, you can create virtual directories by simply prepending your blob name with a directory prefix. Here’s an example of how to create a blob inside a virtual directory:
...
// Get a reference to a blob with a virtual directory
var blob = container.GetBlobReference(@"myvirtualdirectory/testfile.txt");
blob.UploadFile(@"c:\temp\testfile.txt");
After executing the blob creation, the resulting structure will look like this:
“storageAccountUri/nameofyourcontainer/myvirtualdirectory/testfile.txt
This feature allows you to create logical partitions and group data together within your container, but there are some implications, as we will see below.
List blobs in a container###
When listing blobs within a container, you get all the objects that exist at the root level. These objects can be one of the below:
- CloudBlockBlob i.e a block blob like the one we created earlier
- CloudPageBlob i.e a page blob
- CloudBlobDirectory i.e a virtual directory
In effect, when you call the ListBlobs()
method you will need to work out what time of IlistBlobItem you got in your hands, cast it and then access its properties. Let’s see how this works:
var storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("photos");
// Loop over items within the container
foreach (IListBlobItem item in container.ListBlobs())
{
if (item is CloudBlockBlob)
{
var blob = item as CloudBlockBlob;
// do something with the blob
}
else if (item is CloudPageBlob)
{
var pageBlob = item as CloudPageBlob;
// do something with the page
}
else if (item is CloudBlobDirectory)
{
var directory = item as CloudBlobDirectory;
// do something with the directory
}
}
I think that this is nice if you want to work with each blob type, but I believe that in most cases what you are after is to find a blob with a specific name or under a certain directory and do something with it. There are few options ways to do this.
- You can use the full path to the blob e.g. directoryname\blobname.withextension
- You can list blobs using a prefix
ListBlobsWithPrefix()
- Or, if you don’t know exactly where your blob is or how deep in the hierarchy, you can pass a
BlobRequestOptions
parameter in theListBlobs()
method to flatten out the structure within your container as per the example below:
var storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("photos");
var options = new BlobRequestOptions() {UseFlatBlobListing = true;}
foreach (var blobItem in blobClient.ListBlobs (options))
{
// do something with the blobItem
}
Note: Unlike the previous example, if you set the UseFlatBlobListing
property to true, the listing will return an enumerable collection of CloudBlob
objects. No need for casting - yay!
Get data from a blob###
The SDK offers a few options for retrieving data from a blob in a similar manner to uploading data to a blob. The available methods are:
- DownloadByteArray()
- DownloadText()
- DownloadToFile()
- DownloadToStream()
You can use any of these methods based on your needs. In this example, I will use the DownloadText()
method to retrieve the contents of the blob.
var storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
var blobClient = storageAccount.CreateCloudBlobClient();
var blobItem = publicClient.GetBlobReference(@"mypubliccontainer\publicBlob.txt");
var textInBlob = blobItem.DownloadText();
Delete a blob###
Deleting is pretty straightforward but you need to be aware of the options available during this operation, especially if you have created any snapshots against a blob. A blob with associated snapshots cannot be deleted and if you attempt to do so, you will receive a 400 error (Bad Request).
To delete a snapshot with or without snapshots, you can pass the BlobRequestOptions
object to the calling method as per the example below
var storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("mycontainername");
// Retrieve reference to a blob named "myblob.txt".
CloudBlockBlob blockBlob = container.GetBlockBlobReference("mytestblob.txt");
// Indicate whether the associated snapshots should be deleted.
var options = new BlobRequestOptions();
options.DeleteSnapshotsOption = DeleteSnapshotsOption.IncludeSnapshots;
// Delete the blob.
blockBlob.Delete(options);
The possible values for the DeleteSnapshotsOption enum are:
- DeleteSnapshotsOnly: deletes the blob's snapshots only.
- IncludeSnapshots: deletes the blob and its snapshots.
- None: deletes blobs but not snapshots.
Happy coding...