Windows Azure Table Storage in the development environment

Lately I’ve been playing around with Microsoft Azure (for now in the offline development environment only) and it is really easy to get started. However, as easy it is to get your ASP.NET app running, it is a bit more difficult to get access to the storage part (blobs, table storage and queues). There is no straight forward how-to available, at least I couldn’t find one. So I’ve combined some of the resources I’ve found (e.g. the example from Windows Azure Table Storage – Not Your Father’s Database, by Julie Lerman and the PDC09 presentation Windows Azure Tables and Queues Deep Dive, by Jai Haridas) and here it is…

Step 1
Create a new ‘Windows Azure Cloud Service’ project and name it something like CloudServiceDemo, hit ok. Then select an ‘ASP.NET Web Role’ to be included in your cloud service solution and again hit Ok. Now two projects are created, one with roles and configuration and one with the actual ASP.NET web site.

When you run this the ‘Windows Azure Simulation Environment’ starts and your web application appears in your browser (note: at this moment my Queue storage fails with an error that it is being used by another process, something which I haven’t figured out yet).

Step 2
Change two configuration files:

  • In the ServiceDefinition.csdef, add line 3 in the configuration settings:
<ConfigurationSettings>
  <Setting name="DiagnosticsConnectionString" />
  <Setting name="DataConnectionString" />
</ConfigurationSettings>
  • In the ServiceConfiguration.cscfg, add line 3 in the configuration settings:
<ConfigurationSettings>
  <Setting name="DiagnosticsConnectionString" value="UseDevelopmentStorage=true" />
  <Setting name="DataConnectionString" value="UseDevelopmentStorage=true" />
</ConfigurationSettings>

Step 3
Add the following code to the OnStart method of the WebRole.cs

// Setup a handler to update CloudStorageAccount instances when the
// configuration settings change in the service configuration file.
CloudStorageAccount.SetConfigurationSettingPublisher(
  (configName, configSetter) =>
  {
    // Provide the configSetter with the initial value
    configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));

    RoleEnvironment.Changed += (sender, arg) =>
    {
      if (arg.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
          .Any((change) => (change.ConfigurationSettingName == configName)))
      {
        // The corresponding configuration setting has changed, propagate the value
        if (!configSetter(RoleEnvironment.GetConfigurationSettingValue(configName)))
        {
          // In this case, the change to the storage account credentials in the
          // service configuration is significant enough that the role needs to be
          // recycled in order to use the latest settings. (for example, the
          // endpoint has changed)
          RoleEnvironment.RequestRecycle();
        }
      }
   };
   }
 );

Step 4
Create a class that represents the data in the table storage (you need to add a reference to System.Data.Services.Client)

/// <summary>
/// Representation of a movie
/// </summary>
/// <remarks>PartitionKey, RowKey and TimeStamp are required for Azure table storage.</remarks>
[DataServiceKey("PartitionKey", "RowKey")]
public class Movie
{
  /// <summary>
  /// Category of the movie, e.g. Action, SciFi, etc.
  /// </summary>
  public string PartitionKey { get; set; }

  /// <summary>
  /// Title of the movie
  /// </summary>
  public string RowKey { get; set; }

  public DateTime TimeStamp { get; set; }

  public int ReleaseYear { get; set; }
}

Step 5
Now you can create the ‘Movie’ table using a CloudStorageAccount

CloudStorageAccount storageAccount =
  CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

storageAccount.CreateCloudTableClient().CreateTableIfNotExist("Movies");

Step 6
And access the storage using a TableServiceContext

// Create a context
TableServiceContext context =
  new TableServiceContext(storageAccount.TableEndpoint.ToString(), storageAccount.Credentials);

// Add movie
Movie newMovie =
  new Movie { PartitionKey = "Action", RowKey = "An action movie", ReleaseYear = 2005 };
context.AddObject("Movies", newMovie);
context.SaveChanges();

// Get movies
IEnumerable<Movie> movies = from m in context.CreateQuery<Movie>("Movies")
                            where m.PartitionKey == "Action"
                            select m;

Of course this is just a start, now the code has to be placed into specific classes dividing the responsibilities. Something like a StorageContext (which inherits from TableServiceContext) to encapsulate the tablename and the context.CreateQuery, and a MovieRepository to encapsulate the context and the get-, add- and update-methods…