Messaging Between Roles Using Azure Queue Storage

Windows Azure Storage provides us with a message queue service for handling large amounts of messages in a reliable manner. Azure Storage Queues are often used to send messages between a web role and some worker role doing the dirty work for the front end. The messages are very small commands (max. 64KB these days). Once placed on the queue these messages can be handled by one or more worker roles.

In this example we use a worker role to issue a credit check on a couple of companies. Requests are made from the web role by placing a message on the creditchecks queue. A worker role picks up these messages one by one and deletes them from the queue after the work is done.

Place a message on the queue

We have a (fabulous) user interface in our web role for this “Evil Company Credit Check”. To start issuing a credit check we provide a company name and the optional SEC CIK Code.

Goldman Sachs Evil Company Credit Check

When we hit submit we create a CloudQueueClient by calling CreateCloudQueueClient on our Azure Storage account. We get a reference to our creditchecks CloudQueue by calling GetQueueReference and call CreateIfNotExist to be sure we have a queue.

using System.Web.Mvc;
using CreditCheck.Mvc.Models;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
 
namespace CreditCheck.Mvc.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Title = "Evil Company Credit Check";
 
            return View();
        }
 
        [HttpPost]
        public ActionResult RequestCreditCheck(CreditCheckModel model)
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                CloudConfigurationManager.GetSetting("AzureStorage"));
 
            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
            CloudQueue queue = queueClient.GetQueueReference("creditchecks");
 
            queue.CreateIfNotExist();
 
            queue.AddMessage(new CloudQueueMessage(
                                 string.Format("{0}|{1}",
                                               model.CompanyName,
                                               model.CikCode)));
 
            ViewBag.Title = "Evil Company Credit Check";
            ViewBag.Message = "Request sent to queue";
 
            return View(model);
        }
    }
}

Now we create a new CloudQueueMessage. This can be a string or a byte array. In this case it’s a simple string with a company name and the CIK code. We add the message by calling AddMessage on the queue. This places the message on the queue for further processing by the worker role. The web role handles the controlback to the user and is ready to take new requests at this point.

Handle the message

Our worker role has an infinite loop on which the message queue is polled for new messages every ten seconds. If we find a message on the queue we retrieve the message by calling GetMessage with a timespan of 5 seconds. This means the message is hidden from the queue for this time. We need to handle the message within that timeframe. If not, the message will reappear on the queue, waiting to be handled by other workers.

After we get the message we execute the credit check logic. We write the result to the trace log. We delete the message from the queue and check if there is another message waiting. If the queue is empty the routine goes back to sleep again for the next ten seconds.

using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
 
namespace CreditCheck.Worker
{
    public class WorkerRole : RoleEntryPoint
    {
        public override void Run()
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                CloudConfigurationManager.GetSetting("AzureStorage"));
 
            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
            CloudQueue queue = queueClient.GetQueueReference("creditchecks");
 
            while (true)
            {
                CloudQueueMessage message = null;
 
                do
                {
                    message = queue.GetMessage(TimeSpan.FromSeconds(5));
 
                    if (message != null)
                    {
                        Trace.WriteLine(
                            "CreditCheck started for " + message.AsString,
                            "Information");
 
                        // Lengthy credit checking logic
                        Thread.Sleep(1500);
 
                        if (message.AsString.StartsWith("Goldman"))
                        {
                            Trace.WriteLine("Something smells fishy...", "Error");
                        }
                        else
                        {
                            Trace.WriteLine("CreditCheck OK", "Information");
                        }
 
                        queue.DeleteMessage(message);
                    }
                } while (message != null);
 
                Thread.Sleep(10000);
            }
        }
 
        public override bool OnStart()
        {
            ServicePointManager.DefaultConnectionLimit = 12;
 
            return base.OnStart();
        }
    }
}

If we take a look at our worker role in the Windows Azure Compute Emulator we see the credit check messages in the trace output. Just imagine thousands of credit checks handled by multiple instances of our worker role… nicely scalable this way.

Credit Check Worker Role Trace Output

Using a Shared Access Signature to Access a Blob on Azure

Windows Azure Blob Storage is a great place to store large files, as we saw in the previous example. But what if we wanted to control who sees what en when? One convenient way of doing this is by creating and distributing url’s with a Shared Access Signature (sas). By specifying such a Shared Access Signature, you can grant users access for a certain period of time.

Example requirements: We need to upload a new blob. We give users access to this blob for one minute. We only hand the user a single url to the blob.

Create the Shared Access Policy

In our previous example we created a simple MVC application called Blobber. All it is capable of is uploading a file to Windows Azure Blob Storage. We changed the code in the Home controller a bit so the application presents the user the url to the blob after uploading. Here’s the code:

using System;
using System.Web;
using System.Web.Mvc;
using Blobber.Mvc.Models;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
 
namespace Blobber.Mvc.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Title = "Blobber";
 
            return View();
        }
 
        [HttpPost]
        public ActionResult UploadFile(HttpPostedFileBase fileBase, UploadFileResultModel model)
        {
            if (fileBase != null && fileBase.ContentLength > 0)
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                    CloudConfigurationManager.GetSetting("AzureStorage"));
                CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer container = blobClient.GetContainerReference("protectedfiles");
 
                container.CreateIfNotExist();
 
                var policy = new SharedAccessPolicy
                    {
                        SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(1),
                        Permissions = SharedAccessPermissions.Read
                    };
 
                var permissions = new BlobContainerPermissions();
                permissions.SharedAccessPolicies.Add("1minute", policy);
                permissions.PublicAccess = BlobContainerPublicAccessType.Off;
                container.SetPermissions(permissions);
 
                CloudBlob blob = container.GetBlobReference(fileBase.FileName);
                blob.UploadFromStream(fileBase.InputStream);
 
                string sas = blob.GetSharedAccessSignature(new SharedAccessPolicy(), "1minute");
                model.Url = blob.Uri.AbsoluteUri + sas;
            }
 
            return View(model);
        }
    }
}

To provide our user access to the blob for one minute we need to create a Shared Access Policy. The policy sets the permissions to read and the SharedAccessExpiryTime to 1 minute from UtcNow. We add this policy to the SharedAccessPolicies of the container and name it “1minute”. We close our container for the public by setting the PublicAccess property to BlobContainerPublicAccessType Off, which allows no anonymous access. Then we can safely upload the file.

Return the Shared Access Signature

Now all we need is to provide our user a url with a valid Shared Access Signature to get to the blob in the container. We do this by calling the GetSharedAccessSignature method on the blob and provide it with an additional Shared Access Policy for our blob (empty in this case) and the name of the group policy (“1minute”). We append this signature to the blob url and store it in the model’s Url property to transport it to the View. This is what we present to the user:

http://127.0.0.1:10000/devstoreaccount1/protectedfiles/web20expo-oreilly-techweb.jpg?sr=b&si=1minute&sig=6thO2KNGXaI0mLfLo35VNx9aXsi1LjF7Gy2fHjNTiFU%3D

In the query string we see the signed resource (sr) value set to blob (b) and the signed identifier (si) value set to our “1minute” policy. The signature (sig) is a computed HMAC-SHA256 value to prevent tampering with the query string values. The user can access the blob by navigating to the url for one minute.

Shared Access Policy Container Access

After the minute expires, the Blob Storage returns with an XML formatted error message.

<?xml version="1.0" encoding="utf-8"?>
<Error>
  <Code>AuthenticationFailed</Code>
  <Message>
    Server failed to authenticate the request. 
    Make sure the value of Authorization header is formed correctly including the signature.
    RequestId:29b5f5f7-9acb-4a02-90eb-63332a495452
    Time:2012-08-15T09:38:10.2464947Z
  </Message>
  <AuthenticationErrorDetail>
    signed expiry time has to be after signed start time
  </AuthenticationErrorDetail>
</Error>

Upload Large Files to Azure Blob Storage from MVC Application

Windows Azure Blob Storage is specially well suited for storing and serving large files. In a single storage account on Azure you can safely store up to 100TB of files. This example shows the basics of uploading of a block blob to the cloud from a MVC application and make it publicly available.

Windows Azure Blob Storage knows two kinds of blobs. A block blob provides streaming access. These are files like images, videos you name it. Most files are block blobs.

Page blobs gives us a more efficient way to read and write. Frequently changing files like a Virtual Hard Disk.

Change the upload limit

To make uploading large files possible from our MVC application, we need to take of the upload limits first. By default this is a 4MB limit but we can crank it up by changing two settings in Web.config. We take 100MB as a file upload limit. The maxRequestLength is for IIS 6, the maxAllowedContentLength for IIS 7. More on that here.

Note: It may be best to restart your Windows Azure Emulator and IIS Express after making changes to you config file. It happens far too often that the web.config doesn’t get upgraded after a change.

<system.web>
  <!-- other settings -->
<httpRuntime maxRequestLength="104857600" /> <!--100 MB-->
</system.web>
<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="104857600" /> <!--100 MB-->
    </requestFiltering>
  </security>
</system.webServer>

Add the connection string

In order to send our files to the Windows Azure Blob Storage we need to specify a connection string in our Azure Service project’s web role. We do this by right clicking the web role and choose properties and then settings. We call it AzureStorage and leave it on UseDevelopmentStorage=true while still developing locally.

Azure Web Role Settings Connection String

Add the file upload form

For the purpose of this example we add a simple upload form to the Index view. We route the form to the HomeController UploadFile action on submit.

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

As you can see I like to keep my designs minimalistic :mrgreen:

Azure Blob Storage Example Blobber Ui

Write the code

For simplicity, we add the file uploading logic to our HomeController’s UploadFile action.

using System.Web;
using System.Web.Mvc;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
 
namespace Blobber.Mvc.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Title = "Blobber";
 
            return View();
        }
 
        [HttpPost]
        public ActionResult UploadFile(HttpPostedFileBase fileBase)
        {
            if (fileBase != null && fileBase.ContentLength > 0)
            {
                CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                    CloudConfigurationManager.GetSetting("AzureStorage"));
 
                CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
                CloudBlobContainer container =
                    blobClient.GetContainerReference("hugefiles");
 
                container.CreateIfNotExist();
 
                container.SetPermissions(
                    new BlobContainerPermissions
                        {
                            PublicAccess = BlobContainerPublicAccessType.Container
                        });
 
 
                CloudBlob blob = container.GetBlobReference(fileBase.FileName);
 
                blob.UploadFromStream(fileBase.InputStream);
            }
 
            return RedirectToAction("Index");
        }
    }
}

First we get a CloudStorageAccount and provide it with our AzureStorage connection string. Then we get the CloudBlobClient by calling the account’s CreateCloudBlobClient method. We get a reference to the actual blob container called “hugefiles” and create it in case it’s not there by calling CreateIfNotExist on the container. We set the “Free for the Public” BlobContainerPermissions so everyone can access our uploads.

Now we are ready to send some files to the cloud. Get a reference to the blob by calling GetBlobReference and pass it the file name (or any other name for that matter). Then call UploadFromStream and pass it the InputStream (a simple IO stream) and the uploading starts.

View the container contents

In Visual Studio we can use the server explorer to get a listing of each blob storage container. I uploaded a few songs of a nice little local band called Autumn Sun (check ‘m out). Our container is wide upen to the public, so we can access all files directly with a plain url like this one:

http://127.0.0.1:10000/devstoreaccount1/hugefiles/03%20Miss%20tree.m4a.

Azure Blob Storage Container View Server Explorer

Of course, if we want to use the actual Blob storage on Windows Azure, we only need to change the connection string to our storage account credentials in the cloud as decribed here.

Using SQL Membership Provider with SQL Azure

Setting up the SQL Membership Provider with SQL Azure is easy. In fact there’s really not much of a difference with the usual setup. Our SQL database lives in the cloud, and that’s about it. So let us step through the process of adding Membership Provider to our MVC example project; StatsOnAzure.

We used Azure Table Storage in our previous example to give the user access to a list of sample data formerly used in the application. Now this is rather a silly feature, because it shows the sample data of all users of the system. What we really want is access to a list with our own sample data history. Here’s where the SQL Membership Provider comes in handy. We use it to authenticate the user and store and retrieve the sample data with the unique key of the user.

Create a SQL Database on Windows Azure

To create a database for the Membership Provider tables we go our account page on the Windows Azure Manager. We select the SQL databases tab and click Add to start the creation process.

Sql Azure Create Database

We only need a small web edition of this database for our purposes. It scales up to max 5 gig of data storage. Let’s name it StatsOnAzureDb and choose our existing SQL instance located in West Europe (Dublin – Ireland). Click Ok. It takes a few seconds to create our new database.

Sql Azure Sql Databases

Getting the Connection String

All we need now is the connectionstring to this database. Once the database is up and running, click on the database name to go to the details page and click on the “Show connection strings” link. Copy the connection string for ADO.NET. Note that if you want to test the connection from outside of Windows Azure you need to add your IP address to the allowed ip addresses in the firewall rules.

Sql Azure StatsOnAzure database Connection Strings

We go back to Visual Studio, open the Web.config and change the connectionstring from our local development SQL database to our SQL Azure instance.

<connectionStrings>
  <add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="
        Server=tcp:sqlinstance.database.windows.net,1433;
        Database=StatsOnAzureDb;
        User ID=adminaccount@servername;
        Password=xxxxx;
        Trusted_Connection=False;
        Encrypt=True;
        Connection Timeout=30;" />
</connectionStrings>

Securing our Application

We now need to tell our MVC application to use the Membership Provider. Luckily for us this feature is already setup from the boilerplate template. We have a AccountController taking care of registering, logging on and the changing of password operations out of the box. The Membership (and Role) Provider are configured for us in Web.config. So all we need to do is to annotate actions with the Authorize attribute. In our case, we want the user to be logged in to the system before using it. So we secure access to the HomeController by setting the Authorize attribute on the controller itself. Now all actions need a logged in user by default.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using StatsOnAzure.Commands;
using StatsOnAzure.Helpers;
using StatsOnAzure.Models;
using StatsOnAzure.Repositories;
using StatsOnAzure.Services;
 
namespace StatsOnAzure.Controllers
{
    [Authorize]
    public class HomeController : Controller
    {
        //...
    }
}

Testing the Membership Provider

If we hit F5 to debug our application, we experience the expected behavior. Since we’re not logged in to the system, the Membership Provider redirects us to the login page. Here we can register as a new user, if needed, and log in the StatsOnAzure.

SQL Azure Membership Provider MVC LogIn Page

The SQL Membership Provider API creates all tables needed to provide user authentication in our app. If we take a look at our Azure SQL Database Manager we see the familiar Membership tables ready to use.

Sql Azure Membership Tables

Making the SampleDataHistoryItem User Aware

Our StatsOnAzure application shows a list of the ten latest sample data sets of all users. We want this list only to show the items of the logged in user. Now the user is logged in by using the Membership Provider we can use all kinds of information from the logged in account. One of them is the ProviderUserKey. In the SQL Membership Provider this key uniquely identifies the user (as a Guid).

We decide to extend the SampleDataHistoryItem (used in Azure Table Storage) with a ProviderUserKey property. This way we can query for the sample data items added by a specific user.

using System;
using Microsoft.WindowsAzure.StorageClient;
 
namespace StatsOnAzure.Models
{
    public sealed class SampleDataHistoryItem : TableServiceEntity
    {
        public SampleDataHistoryItem()
        {
            PartitionKey = "SampleDataHistory";
            RowKey = Guid.NewGuid().ToString();
        }
 
        public string SampleData { get; set; }
        public string ProviderUserKey { get; set; }
    }
}

Extending the Repository

The repository takes care of getting and modifying the data back and forth from the Azure Table Storage. We need the ProviderUserKey on each query, since we decided that the sample data history items must be from the logged in user. It seems convenient (at least for now) to provide this key in the constructor of the repository and to use it in our queries.

using System.Collections.Generic;
using System.Data.Services.Client;
using System.Linq;
using Microsoft.WindowsAzure.StorageClient;
using StatsOnAzure.Models;
using StatsOnAzure.Services;
 
namespace StatsOnAzure.Repositories
{
    public class SampleDataHistoryRepository
    {
        private readonly string _currentUserProviderUserKey;
        private readonly TableServiceContext _serviceContext;
        private readonly CloudTableClient _tableClient;
 
        public SampleDataHistoryRepository(TableStorageService service, 
            string currentUserProviderUserKey)
        {
            _currentUserProviderUserKey = currentUserProviderUserKey;
            _tableClient = service.StorageAccount.CreateCloudTableClient();
            _serviceContext = _tableClient.GetDataServiceContext();
        }
 
        public static string TableName
        {
            get { return "StatsOnAzure"; }
        }
 
        public static string PartitionKey
        {
            get { return "SampleDataHistory"; }
        }
 
        public DataServiceResponse SaveChanges()
        {
            return _serviceContext.SaveChangesWithRetries();
        }
 
        public void Add(string numbers)
        {
            var sampleDataHistoryItem =
                new SampleDataHistoryItem
                    {
                        SampleData = numbers,
                        ProviderUserKey = _currentUserProviderUserKey
                    };
 
            _serviceContext.AddObject(TableName, sampleDataHistoryItem);
        }
 
        public IEnumerable<SampleDataHistoryItem> GetAll()
        {
            return _serviceContext
                .CreateQuery<SampleDataHistoryItem>(TableName)
                .AsTableServiceQuery<SampleDataHistoryItem>()
                .Where(e => e.PartitionKey == PartitionKey)
                .Where(e => e.ProviderUserKey == _currentUserProviderUserKey)
                .ToList();
        }
 
        public SampleDataHistoryItem GetByRowKey(string key)
        {
            return GetAll()
                .FirstOrDefault(e => e.RowKey == key);
        }
 
        public void RemoveByRowKey(string rowKey)
        {
            SampleDataHistoryItem entity = GetByRowKey(rowKey);
 
            if (entity != null)
            {
                _serviceContext.DeleteObject(entity);
                _serviceContext.SaveChangesWithRetries();
            }
        }
 
        public IEnumerable<SampleDataHistoryItem> GetLatestSampleDataHistory(int count)
        {
            return GetAll()
                .OrderByDescending(e => e.Timestamp)
                .Take(count);
        }
 
        public void RemoveObsoleteSampleDataFromHistory(int skipCount)
        {
            IEnumerable<SampleDataHistoryItem> items = GetAll()
                .OrderByDescending(e => e.Timestamp)
                .Skip(skipCount);
 
            foreach (SampleDataHistoryItem sampleDataHistoryItem in items)
            {
                RemoveByRowKey(sampleDataHistoryItem.RowKey);
            }
        }
    }
}

And that’s all. We only have to provide the ProviderUserKey when we new up the repository. For example from the Index action in the HomeController.

[HttpPost]
public ActionResult Index(NumberModel model)
{
    try
    {
        var repository = new SampleDataHistoryRepository(
            new TableStorageService(),
            GetCurrentUserProviderUserKey());
 
        CrunchNumbers(model);
        SetCrunchedTitles();
 
        repository.Add(model.Numbers);
        repository.SaveChanges();
 
        model.SampleDataHistory = repository.GetLatestSampleDataHistory(NumHistoryItems);
        repository.RemoveObsoleteSampleDataFromHistory(NumHistoryItems);
        repository.SaveChanges();
    }
    catch (Exception)
    {
        model.Numbers = string.Empty;
        SetFailedTitles();
    }
 
    return View(model);
}

And here’s how we get the ProviderUserKey from the Membership Provider.

private static string GetCurrentUserProviderUserKey()
{
    MembershipUser membershipUser = Membership.GetUser();
 
    if (membershipUser == null || membershipUser.ProviderUserKey == null)
        throw new InvalidOperationException(
            "Couldn't get the current provider user key");
 
    return membershipUser.ProviderUserKey.ToString();
}

From now on, all sample data history items will be from the logged in user.

StatsOnAzure V3

Using Windows Azure Table Storage in an ASP.NET MVC application

Looking at Azure Table Storage leaves us developers often puzzled. It’s hard to get a general idea of what it is actually for. Why do we need this NoSQL thing? Storing loads of structured data? That’s why we use SQL server, right? But it’s non-relational. Why? We’re so in love with our relational databases. But is it always necessary to store data that way?

Azure Table Storage is all about storing (possibly huge) ammounts of easy scale-able, non-relational data, blazing fast and easy queryable. Forget about relationships, performance tweaking you indices. Also forget about those DBA’s from hell :mrgreen: or other major constraints. Store all kinds of different entities and retrieve them where and whenever needed.

In this example we build up on the MVC 4 statistics application from the previous post on publishing your app to the cloud. We take that as a starting point. We use Azure Table Storage to present the user a list of ten former sample datasets to reuse. No rocket science. This is what it looks like:

Stats On Azure Gui V2 with Azure Table Storage

Creating an Entity

To use Azure Table Storage you need a poco / model derived from TableServiceEntity. This represents an entity in a Windows Azure table. It adds three public properties required by Azure Table Storage.

  • PartitionKey
    You can see this as the category or cluster your entity belongs to. Used for load balancing. All entities with the same PartitionKey are served from the same place.
  • RowKey
    Provides uniqueness within a given PartitionKey. You can see it as the title or name of your entity.
  • Timestamp
    Read only property to make optimistic concurrency possible.

Our entity provide us with a way to store a single sample data history item to Azure Table Storage. In the constructor we hard coded our PartitionKey as SampleDataHistory and set the RowKey to a random Guid.

using System;
using Microsoft.WindowsAzure.StorageClient;
 
namespace StatsOnAzure.Models
{
    public sealed class SampleDataHistoryItem : TableServiceEntity
    {
        public SampleDataHistoryItem()
        {
            PartitionKey = "SampleDataHistory";
            RowKey = Guid.NewGuid().ToString();
        }
 
        public string SampleData { get; set; }
    }
}

Setting the Connectionstring

So now we need a way to access the Azure Table Storage service. First we need to set up a connectionstring. We do this by right clicking the webrole in our Azure Service project and choose properties and the settings tab. Add and name a connectionstring and set it to UseDevelopmentStorage=true. This way we can test against our local Azure emulator. Later we set this to our actual Table Storage on Windows Azure.

Azure Table Storage Setup Local Connectionstring

Initializing the Table Storage Service

We create a TableStorageService that takes care of connecting and initializing our Cloud Storage Account. It also has a static method that creates the Table if it is not already there.

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
 
namespace StatsOnAzure.Services
{
    public class TableStorageService
    {
        private static readonly CloudStorageAccount _storageAccount =
            CloudStorageAccount.Parse(
                CloudConfigurationManager
                    .GetSetting("TableStorageConnectionString"));
 
        public CloudStorageAccount StorageAccount
        {
            get { return _storageAccount; }
        }
 
        public static void CreateTableIfNotExist(string tableName)
        {
            CloudTableClient tableClient = _storageAccount.CreateCloudTableClient();
 
            tableClient.CreateTableIfNotExist(tableName);
        }
    }
}

We call this code only once on start up. In this case from our Global.asax file. We provide our call to CreateTableIfNotExist with the TableName stored in our Sample Data History Repository (read on).

using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using StatsOnAzure.App_Start;
using StatsOnAzure.Repositories;
using StatsOnAzure.Services;
 
namespace StatsOnAzure
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
 
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
 
            TableStorageService.CreateTableIfNotExist(
                SampleDataHistoryRepository.TableName);
        }
    }
}

Creating the Repository

We build a simple repository for all our Table access. This way we cluster all our data access code in on class, shielding the nitty-gritty details from the rest of our app. This repository does only eager loading.

using System.Collections.Generic;
using System.Data.Services.Client;
using System.Linq;
using Microsoft.WindowsAzure.StorageClient;
using StatsOnAzure.Models;
using StatsOnAzure.Services;
 
namespace StatsOnAzure.Repositories
{
    public class SampleDataHistoryRepository
    {
        private readonly TableServiceContext _serviceContext;
        private readonly CloudTableClient _tableClient;
 
        public SampleDataHistoryRepository(TableStorageService service)
        {
            _tableClient = service.StorageAccount.CreateCloudTableClient();
            _serviceContext = _tableClient.GetDataServiceContext();
        }
 
        public static string TableName
        {
            get { return "StatsOnAzure"; }
        }
 
        public static string PartitionKey
        {
            get { return "SampleDataHistory"; }
        }
 
        public DataServiceResponse SaveChanges()
        {
            return _serviceContext.SaveChangesWithRetries();
        }
 
        public void Add(SampleDataHistoryItem item)
        {
            _serviceContext.AddObject(TableName, item);
        }
 
        public void Add(string numbers)
        {
            var item = new SampleDataHistoryItem {SampleData = numbers};
            Add(item);
        }
 
        public IEnumerable<SampleDataHistoryItem> GetAll()
        {
            return _serviceContext
                .CreateQuery<SampleDataHistoryItem>(TableName)
                .AsTableServiceQuery<SampleDataHistoryItem>()
                .Where(e => e.PartitionKey == PartitionKey)
                .ToList();
        }
 
        public SampleDataHistoryItem GetByRowKey(string key)
        {
            return GetAll()
                .FirstOrDefault(e => e.RowKey == key);
        }
 
        public void RemoveByRowKey(string rowKey)
        {
            SampleDataHistoryItem entity = GetByRowKey(rowKey);
 
            if (entity != null)
            {
                _serviceContext.DeleteObject(entity);
                _serviceContext.SaveChangesWithRetries();
            }
        }
 
        public IEnumerable<SampleDataHistoryItem> GetLatestSampleDataHistory(int count)
        {
            return GetAll()
                .OrderByDescending(e => e.Timestamp)
                .Take(count);
        }
 
        public void RemoveObsoleteSampleDataFromHistory(int skipCount)
        {
            IEnumerable<SampleDataHistoryItem> items = GetAll()
                .OrderByDescending(e => e.Timestamp)
                .Skip(skipCount);
 
            foreach (SampleDataHistoryItem sampleDataHistoryItem in items)
            {
                RemoveByRowKey(sampleDataHistoryItem.RowKey);
            }
        }
    }
}

In the constructor we create the actual Data Service Context by calling GetDataServiceContext on the CloudTableClient. This context allows us to perform data operations against the Table service. The rest of the methods make the calls to the Azure Table, like GetAll and GetByRowKey. We first call the ObjectContext CreateQuery with a particular entity type providing the table name. The we call AsTableServiceQuery to convert the DataServiceQuery to a CloudTableQuery. The latter represents an actual query against the Windows Azure Table service.

Extending the Model

Remember, we want to add a list of the ten latest data samples. So we add to the ol’ Number model a SampleDataHistory property to represent that list.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using StatsOnAzure.Commands;
 
namespace StatsOnAzure.Models
{
    public class NumberModel
    {
        [Required]
        [DataType(DataType.MultilineText)]
        [Display(Name = "Population of double values")]
        public string Numbers { get; set; }
 
        public double Count { get; set; }
        public IEnumerable<ICommand> Statistics { get; set; }
        public IEnumerable<SampleDataHistoryItem> SampleDataHistory { get; set; }
    }
}

Extending the Controller

Now each time the HomeController gets a request to crunch some sample data we store that data value in our Azure Table Storage. We do this by calling methods on the repository to add, retrieve and delete sample data history items.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using StatsOnAzure.Commands;
using StatsOnAzure.Helpers;
using StatsOnAzure.Models;
using StatsOnAzure.Repositories;
using StatsOnAzure.Services;
 
namespace StatsOnAzure.Controllers
{
    public class HomeController : Controller
    {
        private const int NumHistoryItems = 10;
 
        [AllowAnonymous]
        [HttpGet]
        public ActionResult Index(NumberModel model, string rowKey)
        {
            var repository = new SampleDataHistoryRepository(new TableStorageService());
 
            try
            {
                SetHomeTitles();
 
                if (rowKey != null)
                {
                    model.Numbers = repository.GetByRowKey(rowKey).SampleData;
                    repository.RemoveByRowKey(rowKey);
                }
 
                if (!string.IsNullOrEmpty(model.Numbers))
                {
                    CrunchNumbers(model);
                    SetCrunchedTitles();
 
                    repository.Add(model.Numbers);
                    repository.SaveChanges();
                }
 
                model.SampleDataHistory = repository.GetLatestSampleDataHistory(NumHistoryItems);
                repository.RemoveObsoleteSampleDataFromHistory(NumHistoryItems);
                repository.SaveChanges();
            }
            catch (Exception)
            {
                model.Numbers = string.Empty;
                SetFailedTitles();
            }
 
            return View(model);
        }
 
        [AllowAnonymous]
        [HttpPost]
        public ActionResult Index(NumberModel model)
        {
            var repository = new SampleDataHistoryRepository(new TableStorageService());
 
            try
            {
                CrunchNumbers(model);
                SetCrunchedTitles();
 
                repository.Add(model.Numbers);
                repository.SaveChanges();
 
                model.SampleDataHistory = repository.GetLatestSampleDataHistory(NumHistoryItems);
                repository.RemoveObsoleteSampleDataFromHistory(NumHistoryItems);
                repository.SaveChanges();
            }
            catch (Exception)
            {
                model.Numbers = string.Empty;
                SetFailedTitles();
            }
 
            return View(model);
        }
 
        // Crunching numbers and setting titles omitted from listing
    }
}

Extending the View

Finally we have to add some Razor markup in our view to render the sample data history list. It is simply a list of action links. If we click on a link the RowKey is sent back to the controller where the history item is retrieved from the Azure Table Storage. Once retrieved it is used to calculate the statistical values the same way we did in our previous example.

@section sampledatahistory
{
    @if (Model != null && Model.SampleDataHistory != null)
    {
        <h4>
            The last @Model.SampleDataHistory.Count() pieces of sample data</h4>
        foreach (SampleDataHistoryItem sampleDataItem in Model.SampleDataHistory)
        {
            @Html.ActionLink(
                string.Format("{0}", sampleDataItem.SampleData.Substring(
                    0,
                    sampleDataItem.SampleData.Length > 32
                        ? 32
                        : sampleDataItem.SampleData.Length)),
                "Index",
                "Home",
                new {sampleDataItem.RowKey},
                null)
            <br />
        }
    }
}

Using Azure Table Storage

Now we have our app working on the local Azure Emulator, it is time to run it against the real thing. We do this by modifying our connectionstring to tell our app to use the Table Storage on Azure. Right click the Web role for our project and choose properties and the settings tab. Choose our connectionstring and enter the storage account credentials by choosing the proper account name and key:

Azure Storage Account Connection String

If we hit F5 to debug we’re running against the Azure Table Storage in the cloud. Once we’re done we can publish our app to the staging environment on Windows Azure as described here.

Publish an ASP.NET MVC application to the Windows Azure Cloud

In the coming weeks I will be focusing on Windows Azure. If you need to manage highly-available, infinitely scalable applications and services you’ll need a Platform as a Service (PaaS) environment. Or at least that’s what they say at Microsoft. Today I take their highly praised Windows Azure Platform for a spin. I deploy a simple ASP.NET MVC 4 application to a Windows Azure cloud service using nothing more than Visual Studio 2010. Now this should be a flexible, open and rock solid experience.

You need an account on Windows Azure to follow along. They currently offer a free trail for 90 days, so what are you waiting for? For this you’ll get 750 small compute hours, 10 Shared Web Sites, a SQL database, 35GB of storage and 20GB of outbound traffic. Enough to keep you busy for the next three months.

Besides that you need to install the Windows Azure SDK for .NET to publish your applications to Windows Azure and get some nice tools for Azure integrated in Visual Studio.

We build an ASP.NET MVC 4 application that gives the user a simple way to use the statistics library from the previous examples. It is based on the default MVC 4 Internet Application boilerplate template, with all Membership Provider logic stripped away from it so it doesn’t use SQL.

The user is presented with an input box to provide the application a set of comma separated numbers. When the user clicks on the Calculate button the application returns with a list of statistical calculation results. The image below shows the application acting on a sample set of 50 ages (of people on a wedding or something).

Statistics On Azure Screenshot

Now we are not gonna focus too much on the code. So here’s our model. It should speak for itself.

using System.ComponentModel.DataAnnotations;
 
namespace StatsOnAzure.Models
{
    public class NumberModel
    {
        [Required]
        [DataType(DataType.MultilineText)]
        [Display(Name = "Population of double values")]
        public string Numbers { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "Count")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double Count { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "Mean Average")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double Mean { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "Variance")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double Variance { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "Standard Deviation")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double StandardDeviation { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "Lower Quartile")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double LowerQuartile { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "Median")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double MiddleQuartile { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "Upper Quartile")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double UpperQuartile { get; set; }
 
        [DataType(DataType.Text)]
        [Display(Name = "InterQuartile Range")]
        [DisplayFormat(NullDisplayText = "N/A")]
        public double InterQuartileRange { get; set; }
    }
}

The controller does a pretty straightforward conversion from the input string of numbers to an ordered list of doubles. From there we fill our model with calls to the extension methods in the statistics library.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;
using Statistics;
using StatsOnAzure.Models;
 
namespace StatsOnAzure.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Title = "Show me those numbers.";
            ViewBag.Message = "I need to crunch 'm.";
 
            return View();
        }
 
        [AllowAnonymous]
        [HttpPost]
        public ActionResult Index(NumberModel model)
        {
            try
            {
                IOrderedEnumerable<double> numbers = 
                    ParseNumbers(model).OrderBy(n => n);
 
                model.Count = numbers.Count();
                model.Mean = numbers.Mean();
                model.Variance = numbers.Variance();
                model.StandardDeviation = numbers.StandardDeviation();
                model.LowerQuartile = numbers.LowerQuartile();
                model.MiddleQuartile = numbers.MiddleQuartile();
                model.UpperQuartile = numbers.UpperQuartile();
                model.InterQuartileRange = numbers.InterQuartileRange();
 
                ViewBag.Title = "Chrunched.";
                ViewBag.Message = "Yummy pie.";
            }
            catch (Exception)
            {
                model.Numbers = string.Empty;
                ViewBag.Title = "Failed.";
                ViewBag.Message = "That ain't cool.";
            }
 
            return View(model);
        }
 
        private static IEnumerable<double> ParseNumbers(NumberModel model)
        {
            const NumberStyles style =
                NumberStyles.Number | NumberStyles.AllowDecimalPoint;
            CultureInfo culture = CultureInfo.CreateSpecificCulture("en-GB");
 
            string[] splittedNumbers = model.Numbers
                .Replace(" ", string.Empty)
                .Split(',');
 
            var numbers = new List<double>();
 
            foreach (string number in splittedNumbers)
            {
                double n;
 
                if (Double.TryParse(number, style, culture, out n))
                {
                    numbers.Add(n);
                }
            }
 
            return numbers;
        }
    }
}

After playing around with it we are ready to test the application on the Local Azure Emulator. We right click the project and choose “Add Windows Azure Cloud Service Project”. This project let us test the application on the local emulator as well as publish the application to Windows Azure. It shows our one MVC webrole called StatsOnAzure.

Windows Azure Service Project

If we run this project the Local Azure Emulator will fire up and present us with our application running on a local version of IIS (or express). So if this is running smoothly we can send our application to Azure. Just right click the Azure Service project and choose “Publish”. We are presented with the “Publish Windows Azure Application”.

Publish Windows Azure Application

We have no subscription set up yet so click “Sign in to download credentials”. This will take us to a Windows Azure login page. Login to you account and a xml file with .publishsettings extension will be downloaded to your machine. Close the browser.

Back with the Publish Windows Azure Application click Import… and locate the .publishsettings file we just downloaded. You should see your description appear in the dropdown box. Now click next. Since we do not have a cloudservice for our application yet choose “create new…” under Cloud Service. We call our service Statistics and place it in the Western Europe datacenter. When we click OK the name will be checked for utter uniqueness.

Publish Windows Azure Application Settings

We want to publish to our Staging environment, with the Debug build configuration and our Cloud service configuration. We also enable remote desktop (choose any – safe! – password/user combination) and enable Web Deploy. The latter gives us the opportunity to quickly upload changes to our cloud service without republishing the whole application.

Publish Windows Azure Application All Settings

Click next and dwell on our settings summary… Now hit publish, sit back and relax for a couple of minutes while our app is being transported to the staging environment of a newly created Cloud Service on Windows Azure somewhere in western Europe. You can follow the progression made over there in the Windows Azure Activity Log. Once the process is done, we are presented with a GUID based staging URL to our application on cloudapp.net.

Windows Azure Activity Log

Finally we’re here… in the cloud…

Statistics On Azure In The Cloud

Now this is the base application for further study on Windows Azure. In upcoming post we will be looking at typical Azure aspects like table and blob storage, SQL Azure, message queues and so on. I can’t wait ;-)