Azure Blob is a cloud storage service from Azure, and great to master if your web service needs to store binary data and text.
- Index
- Understanding Structure of Blob Service
- CRUD of Container
- CRUD of Blob
The master document of how to is here; https://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/
What is Azure Blob storage?
Azure Blob storage is a service that stores file data in the cloud. Blob storage can store any type of text or binary data, such as a document, media file, or application installer. Blob storage is sometimes referred to as object storage.
OK. Azure Blob sounds like service for almost all web services.
What is Blob Storage
It is a service for storing large amounts of unstructured data, such as text or binary data, that can be accessed from anywhere in the world via HTTP or HTTPS. You can use Blob storage to expose data publicly to the world, or to store application data privately.
Common uses of Blob storage include:Serving images or documents directly to a browser. Storing files for distributed access. Streaming video and audio. Performing secure backup and disaster recovery. Storing data for analysis by an on-premises or Azure-hosted service
Great these are all thing I want to do. Let’s see how we can use this service.
Understanding Structure of Blob Service.
Blob service consist of three layers. Account > Container > Blob
There are three types of blobs, block blobs, page blobs, and append blobs.
You can have unlimited containers in one account, and unlimited number of blobs in one container. But there is limitation within blob, that is;
block blob, 50,000 blocks of up to 4 MB each, for a total size of slightly more than 195 GB (4 MB X 50,000). Page blobs can be up to 1 TB in size, and are more efficient for frequent read/write operations.
OK, time to code. First, obtain all related SDK from Nuget.

Assuming you already have account. (if not please follow the master document and create one) Let’s cover container first.
CRUD of Container
Get List of Containers
To get list of containers that belongs to your account, we simply call ListContainers from the blob client class.
I am storing credential information in Web.config like below;
1 2 3 |
<connectionStrings> <add name="StorageConnectionString" connectionString="DefaultEndpointsProtocol=https;AccountName=[YOUR ACCOUNT NAME HERE];AccountKey=[YOUR PRIME KEY HERE]" /> </connectionStrings> |
And here is
Controllers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Blob; using System.Configuration; namespace Sample.Controllers { public class BlobController : Controller { // GET: Blob public ActionResult Index() { return View(); } // GET: Containers, it returns list of containers public ActionResult Containers(string key) { // Retrieve storage account from connection string. CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString); // Create the blob client. CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); // Retrieve a list of containers and return. return View(blobClient.ListContainers(key)); } } } |
View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
@model IEnumerable<Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer> @{ ViewBag.Title = "Containers"; Layout = "~/Views/Shared/_Layout.cshtml"; } <div class="container"> <h2>Containers</h2> <div class="well"> @using (Html.BeginForm("Containers", "Blob", FormMethod.Post, new { @class = "form-inline" })) { <div class="form-group"> @Html.Label("Container Name", new { @class = "sr-only", @for = "key" }) @Html.TextBox("key", "", new { @placeholder = "Type in container name here", @class = "form-control" }) </div> <button type="submit" class="btn btn-default">Search</button> } </div> <hr /> <div class="list-group"> @foreach (var item in Model) { <a href="#" class="list-group-item"> <h4 class="list-group-item-heading">Name: @item.Name</h4> <p class="list-group-item-text"> Last Modified: @item.Properties.LastModified.ToString()<br /> Lease Duration: @item.Properties.LeaseDuration.ToString()<br /> Lease State: @item.Properties.LeaseState.ToString()<br /> Lease Status: @item.Properties.LeaseStatus.ToString()<br /> ETag: @item.Properties.ETag.ToString() <hr /> URI: @item.StorageUri.PrimaryUri.AbsoluteUri.ToString() </p> </a> } </div> </div> |
There is no custom model involved in this. I just simply use model, Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer. After you execute, you should see web page like below.
I now see that I currently have two containers for this account.
Create Container
Now let’s take a look at how to create new container. Container is simple, it really is just a container and not much else.
Here, I am taking string variable name, then I m creating blob container class from blob client, then attempt to get reference to the container. Then call CreateIfNotExist action. I think this can be more friendly, like handling cases when specific container exist etc.. or validate name format, but I ll get to that later.
Controllers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Blob; using System.Configuration; namespace Sample.Controllers { public class BlobController : Controller { // GET: ContainerCreate public ActionResult ContainersCreate() { // I just simply return view return View(); } // POST: ContainerCreate [HttpPost] [ValidateAntiForgeryToken] public ActionResult ContainersCreate(string name) { // Retrieve storage account from connection string. CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString); // Create the blob client. CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); // Retrieve a reference to the container CloudBlobContainer container = blobClient.GetContainerReference(name); // Create the container if it doesn't already exist. container.CreateIfNotExists(); // after adding new container, return to list of containers return RedirectToAction("Containers"); } } } |
View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
@{ ViewBag.Title = "Create Container"; Layout = "~/Views/Shared/_Layout.cshtml"; } <div class="container"> <h2>Create Container</h2> <hr /> @using (Html.BeginForm("ContainersCreate", "Blob", FormMethod.Post, new { @class = "form-inline" })) { @Html.AntiForgeryToken() <div class="form-group"> @Html.Label("Container Name", new { @for = "name" }) @Html.TextBox("name", "", new { @class = "form-control", @placeholder = "Type in container name here" }) </div> <button type="submit" class="btn btn-default">Create</button> } <hr /> <h3>Container naming rules</h3> <p> A container name must be a valid DNS name and conform to the following rules: </p> <p> A container name must be all lowercase. 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. Container names must be from 3 through 63 characters long. </p> </div> |
This is the view,
and great, now I see my 3rd container created with name I specified.
One of the main thing you can do with container is set access level. You notice that Public Access is off by default. Let’s see how we can make this publicly accessible container later.
Now that we have container covered, let’s look at blob part.
CRUD of blob
Get list of blob for specific container
You notice I created function to retrieve blob client, since I was repeatedly calling to create blob client.
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Net; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Blob; using System.Configuration; namespace Sample.Controllers { public class BlobController : Controller { private CloudStorageAccount storageAccount() { // Return storage account return CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString); } private CloudBlobClient blobClient() { // Return blob client return storageAccount().CreateCloudBlobClient(); } public ActionResult Blobs(string containerName) { // You have to have containerName if (containerName == null) { return new HttpStatusCodeResult(HttpStatusCode.BadRequest); } // Get Container CloudBlobContainer container = blobClient().GetContainerReference(containerName); // To show container name ViewBag.ContainerName = containerName; return View(container.ListBlobs()); } } } |
View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
@model IEnumerable<Microsoft.WindowsAzure.Storage.Blob.IListBlobItem> @{ ViewBag.Title = "Blobs"; Layout = "~/Views/Shared/_Layout.cshtml"; } <div class="container"> <h1>@ViewBag.ContainerName</h1> <hr /> <a href="@Url.Action("BlobCreate","Blob")" class="btn btn-default">Upload New Blob</a> <hr /> <div class="list-group"> @foreach (var item in Model) { <a href="#" class="list-group-item"> URL: @item.StorageUri<br/> </a> } </div> </div> |
Then you should see the whole list of blob under the container nvideospace like below.
Now, Let’s upload blob into the container.
Upload (Create) Blob
On first run, I was getting “404.13 Content Length Too Large” error. If you are trying to upload large file like video file, you are likely to exceed default file size limit and get an error. You ll need to go to your Web.config and set limit like below.
1 2 3 4 5 6 7 8 9 10 |
<system.web> <httpRuntime targetFramework="4.6" maxRequestLength="2147483647" /> </system.web> <system.webServer> <security> <requestFiltering> <requestLimits maxAllowedContentLength="2147483647"/> </requestFiltering> </security> </system.webServer> |
I have heard default is 4Mb, but anyhow I ll change it to 2147483647, which is max number allowed. File size limitation is checked at application level and server level, so you will need to set both. It wouldn’t make sense to have different limitation so I set both at 2147483647. I want to dig more into file size and type of videos later to understand how these limitations should be set.
Controllers
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Net; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Auth; using Microsoft.WindowsAzure.Storage.Blob; using System.Configuration; namespace Sample.Controllers { public class BlobController : Controller { private CloudStorageAccount storageAccount() { // Return storage account return CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString); } private CloudBlobClient blobClient() { // Return blob client return storageAccount().CreateCloudBlobClient(); } // GET: CreateBlob public ActionResult BlobCreate() { // map select box to list of cotainer here ViewBag.containerName = new SelectList(blobClient().ListContainers(), "Name", "Name"); return View(); } // POST: CreateBlob [HttpPost] [ValidateAntiForgeryToken] public ActionResult BlobCreate(string containerName, string blobName, HttpPostedFileBase file) { // Retrieve reference to container variable value containerName. CloudBlobContainer container = blobClient().GetContainerReference(containerName); // Retrieve reference to a blob variable value blobName CloudBlockBlob blockBlob = container.GetBlockBlobReference(blobName); // Create or overwrite the blob with contents from a local file. blockBlob.UploadFromStream(file.InputStream); // After adding new blob, return to list blob at specific container return RedirectToAction("Blobs", new { containerName = containerName}); } } } |
View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
@{ ViewBag.Title = "Upload Blob"; Layout = "~/Views/Shared/_Layout.cshtml"; } <div class="container"> <h1>Upload Blob</h1> <div class="well"> @using (Html.BeginForm("BlobCreate", "Blob", FormMethod.Post, new { @enctype="multipart/form-data", @class = "form-horizontal" })) { @Html.AntiForgeryToken() <div class="form-group"> @Html.Label("Select Container", new { @class = "col-sm-2 control-label", @for = "containerName" }) <div class="col-sm-10"> @Html.DropDownList("containerName", null, htmlAttributes: new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.Label("Blob Name", new { @class = "col-sm-2 control-label", @for = "blobName" }) <div class="col-sm-10"> @Html.TextBox("blobName", "", new { @class = "form-control", @placeholder = "Type in blob name here" }) </div> </div> <div class="form-group"> @Html.Label("File", new { @class = "col-sm-2 control-label", @for = "file" }) <div class="col-sm-10"> @Html.TextBox("file", "", new { @class = "form-control", @type = "file" }) </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">Upload</button> </div> </div> } </div> </div> |
So the interface to upload blob looks like below. A user needs select container where they want to upload blob to, and name of blob, then select file from local. You will need to make sure you have specified enctype at form to multipart/form-data, in order to retrieve streaming file from the local machine of the user. You can do so along with html attribute you pass at Html.BeginForm.
Here, I am getting a list of containers and dump them into ViewBag and map them on drop down list for a user to select.
After upload is complete, I redirect user to the list of blob for the specific container, and now you should see the file you just upload like below.
Serving Blob
I will update more on how you can make more friendly interfaces, and doing uploads at back-ends, connecting to Azure media services etc.