The scenario

I have an ASP.NET web application, which is used to search and navigate over a very large number of aerial images. Currently there are nearly 400.000 images consuming 2 TB of storage + backups.

image

I thought it would be a good idea to see how the Windows Azure Blob storage could be used to store the aerial photos for my application. I wanted to do this without moving the entire web application to Windows Azure (taking one step at a time). Since Windows Azure currently is in beta, I only have about 50GB of cloud storage to play with. Therefore, I will start by moving all the lower resolution images to the Windows Azure Blob Storage.

Create a new Storage Project in Windows Azure

Before we can start to upload the images to the Windows Azure Blob Storage, we need to create a new Storage Account in the Azure Services Developer Portal:

image

When you go through the process for creating a new Storage Account, you will get the required Endpoints and Access Keys for working with the Blob Storage from your code.

Uploading the Images to Windows Azure Blob Storage

To upload the images from my local storage to the Windows Azure Blob Storage in the Microsoft cloud datacenter, I decided to write a small and simple console program. This would iterate through all the image files in a given directory and upload each image. From my datacenter in Norway, this process would typically upload between 4000 and 6000 images per hour for small 50 kB thumbnail images.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Samples.ServiceHosting.StorageClient;
using System.Collections.Specialized;
using Microsoft.ServiceHosting.ServiceRuntime;
using System.IO;
using MapaidLibrary.BusinessLogic;
using MapaidLibrary.Entities;

namespace UploadPhotos
{
    class Program
    {
        static string sourceDirectory = @"\\leopard\mapaid\photos\l1";
        static string targetContainer = "photosl1";

        static BlobContainer _Container = null;

        static void Main(string[] args)
        {
            // Get the configuration from the cscfg file
            StorageAccountInfo accountInfo = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();

            // Container names have the same restrictions as DNS names
            BlobStorage blobStorage = BlobStorage.Create(accountInfo);
            _Container = blobStorage.GetBlobContainer("photosl1");

            // Make the container public so that we can hit the URLs from the web
            _Container.CreateContainer(new NameValueCollection(), ContainerAccessControl.Public);

            var files = from file in Directory.GetFiles(sourceDirectory) select file;

            int i = 0;

            DateTime startTime = DateTime.Now;
            foreach (string file in files)
            {
                UploadPhoto(file);
                i++;
            }

        }

        static void UploadPhoto(string fromPath)
        {
            try
            {
                FileStream fs = File.OpenRead(fromPath);

                byte[] data = new byte[fs.Length];
                fs.Read(data, 0, data.Length);
                fs.Close();

                string blobFilename = Path.GetFileName(fromPath);
                BlobProperties properties = new BlobProperties(blobFilename);

                // Create metadata to be associated with the blob
                NameValueCollection metadata = new NameValueCollection();
                metadata["FileName"] = blobFilename;

                properties.Metadata = metadata;
                properties.ContentType = "image/jpeg";

                //// Create the blob
                BlobContents fileBlob = new BlobContents(data);
                bool ok = _Container.CreateBlob(properties, fileBlob, true);
            }
            catch (FileNotFoundException ex)
            {
                Console.WriteLine("File not found: " + fromPath);
            }

        }
    }
}

This needs to be added to the App.config file:

<appSettings>
    <add key="AccountName" value="YourAccount"/>
    <add key="AccountSharedKey" value="YourSharedKey/"/>
    <add key="BlobStorageEndpoint" value="http://blob.core.windows.net"/>
</appSettings>

Using the images from the Windows Azure Blob Storage

After uploading all the images, I would now be able to access the images by a simple URL like this:

http://youraccount.blob.core.windows.net/photosl1/50389339.jpg

In my ASP.NET web application, I simply had to change the URL of an ASP.NET Image tag like this:

<asp:Image runat="server" Width="193" Height="128" ImageUrl='<%# Eval("PhotoId", "http://youraccount.blob.core.windows.net/photosl1/{0}.jpg") %>'

Now my aerial images are served directly from a Windows Azure datacenter!

I have been using the Windows Azure Blob Storage for a few months now (since the PCD 2008) and even if the service is in beta, I have not experienced any issues accessing the images from my web application.