Building a Storage Account helper class (and forget about it)

When you use storage with the managed API’s, you always need to use a storage account, and make sure you setup the whole thing correctly. The way to do this is slightly different when building a web role versus a worker role, so I decided to tackle this problem by building a simple class that takes care of everything, and works the same in a web or worker role. All you need is to copy/reference this class in each of your projects.

1. The first problem – setting up the ConfigurationSettingPublisher

The storage account uses a connection string. This connection string can come from the normal web.config (when you use storage in a local web site) or the Azure project’s ServiceConfiguration.cscfg. To allow all connections to be available in both environments the storage account uses a ConfigurationSettingPublisher, which is a delegate that retrieves the connection.

Code Snippet
  1. CloudStorageAccount.SetConfigurationSettingPublisher(
  2.   (config, setter) =>
  3.   {
  4.     setter(
  5.       RoleEnvironment.IsAvailable ?
  6.         RoleEnvironment.GetConfigurationSettingValue(config)
  7.         :
  8.         ConfigurationManager.AppSettings[config]
  9.     );
  10.   });


Problem is where to put the code; in a web role you have to put the code in startup code, so you need to put this in Global.asax. In a worker role there is no such thing, so you put this in the worker role’s Start method. So, you might say, let’s also put this code in the Start method of the web role; this will run in another process so you end up without a proper initialized web role…

So here is my solution: create a new class MyStorageAccount which uses a static constructor (also known as the type constructor) so call this code. A static constructor will automatically be called by the runtime when you first use the class. So this way you will always have correct initialization, and only when you need it:

Code Snippet
  1. using System.Configuration;
  2. using Microsoft.WindowsAzure;
  3. using Microsoft.WindowsAzure.ServiceRuntime;
  5. namespace MessagesLib
  6. {
  7.   public static class MyStorageAccount
  8.   {
  9.     public static string DataConnection = "DataConnection";
  11.     public static CloudStorageAccount Instance
  12.     {
  13.       get
  14.       {
  15.         return CloudStorageAccount.FromConfigurationSetting(DataConnection);
  16.       }
  17.     }
  19.     static MyStorageAccount()
  20.     {
  21.       CloudStorageAccount.SetConfigurationSettingPublisher(
  22.         (config, setter) =>
  23.         {
  24.           setter(
  25.             RoleEnvironment.IsAvailable ?
  26.               RoleEnvironment.GetConfigurationSettingValue(config)
  27.               :
  28.               ConfigurationManager.AppSettings[config]
  29.           );
  30.         });
  31.     }
  32.   }
  33. }

This class uses the static constructor to setup the ConfigurationSettingPublisher, and also has an Instance property. This allows you to retrieve the storage account without always having to provide the connection configuration name. Most applications will only use a single connection, so this should work fine.

So instead of writing this all the time:

Code Snippet
  1. var account = CloudStorageAccount.FromConfigurationSetting("DataConnection");
  2. var tableClient =
  3.   account.CreateCloudTableClient();


You can now write it like this:

Code Snippet
  1. var account = MyStorageAccount.Instance;
  2. var tableClient =
  3.   account.CreateCloudTableClient();


Or even shorter:

Code Snippet
  1. var tableClient =  MyStorageAccount.Instance.CreateCloudTableClient();


Much easier!

2. Handling configuration changes

Next problem is when the configuration of the role is updated. In this case you need to check if you can handle this change, if not, you should restart the role. Typical code for this looks like this:

Code Snippet
  1. RoleEnvironment.Changing += (_, changes) =>
  2. {
  3.   if (changes.Changes
  4.              .OfType<RoleEnvironmentConfigurationSettingChange>()
  5.              .Any(change => change.ConfigurationSettingName == config))
  6.   {
  7.     if (!setter(RoleEnvironment.GetConfigurationSettingValue(config)))
  8.     {
  9.       RoleEnvironment.RequestRecycle();
  10.     }
  11.   }
  12. };


We register for the Changing event. When this event gets raised, you receive all the changes in a collection. You walk the collection to see if the configuration you’re interested in is part of the collection. In that case you need to re-invoke the ConfigurationSettingPublisher, and when that method returns false you need the recycle the role. Please note that this will only happen when running as a role (not local web site) so we can use the cloud version to retrieve configuration…

So what is the result of this? No need to call special code in your Global.asax or worker role Start method. It just works!