How to Use Windows Azure Blob Storage Service With ASP.NET MVC Web Application

This blog post provides a Windows Azure Blob Storage example which walks you through on how to use Blob Storage service with ASP.NET MVC.
2012-01-18 09:17
Tugberk Ugurlu


I have been digging into Windows Azure more and more lately. I wish that it would be supported in Turkey but anyway, emulator is my cloud for now Smile Yesterday, I thought I should note some of things down and told myself "There is no better place than your blog for that, my friend" and here I am.

One feature of Windows Azure platform which I will be using is Blob Storage. Blob storage enables you to store your unstructured data (like pictures, word docs, excel file, etc.) inside Windows Azure servers and access them over HTTP or HTTPS. With Windows Azure .Net SDK, you have full control over your blobs and program against that easily. How? Let’s see.

Before starting, make sure that you have installed Windows Azure SDK for .Net which will bring down Windows Azure Tools for Microsoft Visual Studio and Windows Azure Client Libraries for .Net. You can find the information on how to install the SDK from http://www.windowsazure.com/en-us/develop/net/

First thing is first. We need an ASP.NET MVC project to simulate this (but it doesn’t have to be ASP.NET MVC project). We have two options to make our application azure-cloudy:

Directly Create a Cloud Application

Inside the new project dialog box on Visual Studio, choose Windows Azure Project as indicated below:

image

When you hit OK, you will see a dialog as below:

image

This dialog box is like a open buffet, you can choose which project you need for your application here. But we will choose ASP.NET MVC 3 Web Role and then hit OK:

image

Then we will see a dialog box which is owned by ASP.NET MVC. From now on everything is same like it is a standard ASP.NET MVC project.

Make Your Application Azure-Cloudy Later

Assuming that we have an existing ASP.NET MVC application and we want to run this application on Windows Azure. What we need to do is to right click on our project and choose "Add Windows Azure Deployment Project Option" as below:

image

Either way, our solution will look something like this:

image

Configure to Work With Blob Storage

We have a few steps to make before we can start developing. In a real world scenario, you need a Windows Azure storage account to use the blob storage service and you can create this account from Windows Azure Management Portal. After you configure your account, you will have your access keys to that storage account which you will need on your development process.

One thing to mention before going further is that you will be able to access your files through HTTP or HTTPS as motioned before and the URL for your blobs will look like this:

http://<storage account>.blob.core.windows.net/<container>/<blob>

There is a way to change this so that you can use your own domain. In our example, we will be reaching out our blobs through localhost. we will get to that later in this post.

In order to develop locally with emulator, we do not need a storage account which means that we don’t need access keys. In order to configure it so, right click on the web role file and choose Properties.

image

This action will brings up the properties windows. From there, go to Settings tab and click add settings and on the new created node, select Connection String as Type and click "..." which stands right hand side.

image

This action will also open up a new window for you and this is where you configure your storage account. But we will choose "Use the Windows Azure storage emulator" option and give this configuration a new friendly name:

image

Those actions are not required but viewed as a best practice while working windows azure cloud projects. Also, you can use Windows Azure Storage and run your application inside your own servers. It is totally fine. So, in that case you won’t need a cloud project. What .Net SDK provides is a wrapper around Windows Azure REST APIs which makes it easy to program against.

Now we are all set and finally we can write some code.

First of all, we need two additional libraries to develop against Windows Azure with .Net:

  • Microsoft.WindowsAzure.StorageClient.dll
  • Microsoft.WindowsAzure.ServiceRuntime.dll

Those two will give us everything we need. For the sake of simplicity, I created a simple project which uploads images through Windows Azure Storage service and list those images on a page. In order to do that so, I created a service class (which is a standard class, nothing further than that) called MyBlobStorageService. Let’s see the code first:

 

 

public class MyBlobStorageService {

    public CloudBlobContainer GetCloudBlobContainer() {

        // Retrieve storage account from connection-string
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                RoleEnvironment.GetConfigurationSettingValue("StorageConnectionString")
            );

        // Create the blob client 
        CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

        // Retrieve a reference to a container 
        CloudBlobContainer blobContainer = blobClient.GetContainerReference("albums");

        // Create the container if it doesn't already exist
        if (blobContainer.CreateIfNotExist()) {

            blobContainer.SetPermissions(
               new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob }
            );
        }

        return blobContainer;
    }

}

What this code does it fairly simple. It gets the storage account information form the connection string that we have configured and creates a CloudStorageAccount class according to that. Then, We create a blob storage client (CloudBlobClient) over that storage account. Finally, we create a container (CloudBlobContainer) for our blobs and check if it exists of not. If not, then we simply create it and set the public access permission to it because we will store images inside that container and we want to display those images on our web page.

In order to demonstrate this, I have two controller actions. One is for HTTP GET and the other is for HTTP POST. Here is the complete controller code:

 

public class HomeController : Controller {

    public MyBlobStorageService 
        _myBlobStorageService = new MyBlobStorageService();

    public ActionResult Index() {

        // Retrieve a reference to a container 
        CloudBlobContainer blobContainer = 
            _myBlobStorageService.GetCloudBlobContainer();

        List<string> blobs = new List<string>();

        // Loop over blobs within the container and output the URI to each of them
        foreach (var blobItem in blobContainer.ListBlobs())
            blobs.Add(blobItem.Uri.ToString());

        return View(blobs);
    }

    [HttpPost]
    [ActionName("index")]
    public ActionResult Index_post(HttpPostedFileBase fileBase) {

        if (fileBase.ContentLength > 0) {

            // Retrieve a reference to a container 
            CloudBlobContainer blobContainer = 
                _myBlobStorageService.GetCloudBlobContainer();

            CloudBlob blob = 
                blobContainer.GetBlobReference(fileBase.FileName);
            
            // Create or overwrite the "myblob" blob with contents from a local file
            blob.UploadFromStream(fileBase.InputStream);

        }

        return RedirectToAction("index");
    }   
}

And the view code is simple as well:

@model List<string>           
@{
    ViewBag.Title = "My Cloudy Album";
}

<h2>My Cloudy Album</h2>

@foreach (var item in Model) {
    <img src="@item" width="200" height="100" />
}

@using (Html.BeginForm("index", "home",  
    FormMethod.Post, new { enctype = "multipart/form-data" })) {
    
    <input type="file" name="fileBase" />
    <p>
        <input type="submit" value="Upload" />
    </p>    
}

Now we are all set and go to go.

But (a big but), you need to run Visual Studio with admin rights in order to run the emulator. Otherwise, you won’t be able to.

image

When we hit CTRL + F5, VS will create a cloud deployment package and deploy it to emulator and we will see the emulator starting up:

image

Now we are cloudy!

image

When we choose a picture and upload it, we should be able to see it after we got back.

image

One more thing to prove that we really run inside the emulator is to right click the emulator icon, choose Show Storage Emulator UI:

image

This will bring up the Storage Emulator as below:

image

On the right hand side, there is a reset button. Click it to reset the emulator and go back to your page and refresh. You will see that all the pictures that you have uploaded are gone now.

That’s all for now Winking smile

Additional Resources



Comments

Manoj Verma
by Manoj Verma on Saturday, Mar 17 2012 12:40:44 +02:00

This is the exact article for which  I'm looking. In my project I need some thing like this to complete my task. Thanks for sharing this article with us, you made it very simple and understandable. I think it helped me as developer as well beginner too. Some nice stuff too helped me in completing task and it having wonderful explanation on Creating Blob Service in windows azure. you may check it....

http://www.mindstick.com/Articles/672676f4-11c0-4dea-ab82-719c99ddcf2d/?Create%20Blob%20Service%20in%20Windows%20Azure

http://blogs.msdn.com/b/windowsazurestorage/archive/2011/02/18/windows-azure-blob-md5-overview.aspx

http://www.codeproject.com/Articles/297052/Azure-Storage-Blobs-Service-Working-with-Directori

So I would like to say thanks everyone for their nice post.

Azure Learner
by Azure Learner on Tuesday, Jan 22 2013 07:23:30 +02:00

Best artical to understand blob concepts of windows azure, as I am new in MVC also so faced some issue regarding MVC but those have been short out and now the code is working fine for me too.

Mina
by Mina on Wednesday, Feb 27 2013 22:11:18 +02:00

Merci pour votre travail, c'est vraiment intéréssant, je voudrais bien que vous le terminez :)

Mayank
by Mayank on Tuesday, Mar 05 2013 07:18:58 +02:00

I am new in Windows Azure Blob Storage Service.

I want to downalod file from Windows Azure Blob Storage Service. So, how can i do this.

Please give me reply because it's relay helpfull for me.

Thanx in Advance.

Ric
by Ric on Friday, Mar 22 2013 15:59:38 +02:00

Great tutorial!

anil
by anil on Tuesday, Aug 27 2013 06:58:33 +03:00

How can i upload multible multible images to azure,

Can you please give me code for this

anil
by anil on Tuesday, Aug 27 2013 08:42:32 +03:00

I am getting following error message

Object reference not set to an instance of an object.

ANIL
by ANIL on Thursday, Aug 29 2013 09:19:30 +03:00

This is my code for Uploading multiple images to azure,

This is my code,I am running this code Getting the following Error:

Error 2 foreach statement cannot operate on variables of type 'System.Web.HttpPostedFileBase' because 'System.Web.HttpPostedFileBase' does not contain a public definition for 'GetEnumerator' D:\DRIVE(D)\mindstick(Practice\NotousProducts\MvcWebRole1\Controllers\ProductsController.cs 64 21 MvcWebRole1

View:

@model MvcWebRole1.Models.Product

 

@{

    ViewBag.Title = "Create";

}

 

<h2>Create</h2>

 

@using (Html.BeginForm("Create","Products",FormMethod.Post, new { enctype = "multipart/form-data" })) {

    @Html.AntiForgeryToken()

    @Html.ValidationSummary(true)

 

    <fieldset>

        <legend>Product</legend>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Name)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Name)

            @Html.ValidationMessageFor(model => model.Name)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Description)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Description)

            @Html.ValidationMessageFor(model => model.Description)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Price)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Price)

            @Html.ValidationMessageFor(model => model.Price)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Image)

        </div>

        <div class="editor-field">

            @*@Html.EditorFor(model => model.Image)*@

            <input type="file" name="fileBase" id="filebase1" />

            @Html.ValidationMessageFor(model => model.Image)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Image1)

        </div>

        <div class="editor-field">

            @*@Html.EditorFor(model => model.Image1)*@

            <input type="file" name="fileBase" id="filebase2" />

            @Html.ValidationMessageFor(model => model.Image1)

        </div>

 

        <p>

            <input type="submit" value="Create" />

        </p>

    </fieldset>

}

 

<div>

    @Html.ActionLink("Back to List", "Index")

</div>

 

@section Scripts {

    @Scripts.Render("~/bundles/jqueryval")

}

 

[HttpPost]

        public ActionResult Create(Product p,HttpPostedFileBase fileBase)

        {         

                if (fileBase.ContentLength > 0)

                {

                    foreach (IEnumerable<HttpPostedFileBase> image in fileBase)

                   {

                        // Retrieve a reference to a container 

                        CloudBlobContainer blobContainer = _myBlobStorageService.GetCloudBlobContainer();

                        CloudBlob blob = blobContainer.GetBlobReference(fileBase.FileName);

 

                        // Create or overwrite the "myblob" blob with contents from a local file

                        blob.UploadFromStream(fileBase.InputStream);

                   }

                }

            }                  

                //secode

              CloudBlobContainer blobContainer1 =_myBlobStorageService.GetCloudBlobContainer();

            CloudBlob blob1 = blobContainer1.GetBlobReference(fileBase.FileName);

 

            CloudBlobContainer blobContainer112 = _myBlobStorageService.GetCloudBlobContainer();

            CloudBlob blob112 = blobContainer112.GetBlobReference(fileBase.FileName);

 

            List<string> blobs = new List<string>();

            // Loop over blobs within the container and output the URI to each of them

            foreach (var blobItem in blobContainer1.ListBlobs())

               blobs.Add(blobItem.Uri.ToString());                            

 

                // TODO: Add insert logic here

                //Product p1 = new Product();

                p.Image = blob1.Uri.ToString();

                p.Image1 = blob112.Uri.ToString();

                db.Products.InsertOnSubmit(p);

                db.SubmitChanges();

                return RedirectToAction("Index");

 

        }

ANIL
by ANIL on Thursday, Aug 29 2013 09:38:10 +03:00

This is my code for Uploading multiple images to azure,

This is my code,I am running this code Getting the following Error:

Error 2 foreach statement cannot operate on variables of type 'System.Web.HttpPostedFileBase' because 'System.Web.HttpPostedFileBase' does not contain a public definition for 'GetEnumerator' D:\DRIVE(D)\mindstick(Practice\NotousProducts\MvcWebRole1\Controllers\ProductsController.cs 64 21 MvcWebRole1

View:

@model MvcWebRole1.Models.Product

 

@{

    ViewBag.Title = "Create";

}

 

<h2>Create</h2>

 

@using (Html.BeginForm("Create","Products",FormMethod.Post, new { enctype = "multipart/form-data" })) {

    @Html.AntiForgeryToken()

    @Html.ValidationSummary(true)

 

    <fieldset>

        <legend>Product</legend>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Name)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Name)

            @Html.ValidationMessageFor(model => model.Name)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Description)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Description)

            @Html.ValidationMessageFor(model => model.Description)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Price)

        </div>

        <div class="editor-field">

            @Html.EditorFor(model => model.Price)

            @Html.ValidationMessageFor(model => model.Price)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Image)

        </div>

        <div class="editor-field">

            @*@Html.EditorFor(model => model.Image)*@

            <input type="file" name="fileBase" id="filebase1" />

            @Html.ValidationMessageFor(model => model.Image)

        </div>

 

        <div class="editor-label">

            @Html.LabelFor(model => model.Image1)

        </div>

        <div class="editor-field">

            @*@Html.EditorFor(model => model.Image1)*@

            <input type="file" name="fileBase" id="filebase2" />

            @Html.ValidationMessageFor(model => model.Image1)

        </div>

 

        <p>

            <input type="submit" value="Create" />

        </p>

    </fieldset>

}

 

<div>

    @Html.ActionLink("Back to List", "Index")

</div>

 

@section Scripts {

    @Scripts.Render("~/bundles/jqueryval")

}

 

[HttpPost]

        public ActionResult Create(Product p,HttpPostedFileBase fileBase)

        {         

                if (fileBase.ContentLength > 0)

                {

                    foreach (IEnumerable<HttpPostedFileBase> image in fileBase)

                   {

                        // Retrieve a reference to a container 

                        CloudBlobContainer blobContainer = _myBlobStorageService.GetCloudBlobContainer();

                        CloudBlob blob = blobContainer.GetBlobReference(fileBase.FileName);

 

                        // Create or overwrite the "myblob" blob with contents from a local file

                        blob.UploadFromStream(fileBase.InputStream);

                   }

                }

            }                  

                //secode

              CloudBlobContainer blobContainer1 =_myBlobStorageService.GetCloudBlobContainer();

            CloudBlob blob1 = blobContainer1.GetBlobReference(fileBase.FileName);

 

            CloudBlobContainer blobContainer112 = _myBlobStorageService.GetCloudBlobContainer();

            CloudBlob blob112 = blobContainer112.GetBlobReference(fileBase.FileName);

 

            List<string> blobs = new List<string>();

            // Loop over blobs within the container and output the URI to each of them

            foreach (var blobItem in blobContainer1.ListBlobs())

               blobs.Add(blobItem.Uri.ToString());                            

 

                // TODO: Add insert logic here

                //Product p1 = new Product();

                p.Image = blob1.Uri.ToString();

                p.Image1 = blob112.Uri.ToString();

                db.Products.InsertOnSubmit(p);

                db.SubmitChanges();

                return RedirectToAction("Index");

 

        }

New Comment