Monthly Archives: July 2010

You are browsing the site archives by month.

Azure Storage Client helpers

In my last post, I described how the configuration setting publisher worked. More specifically, I covered how to use the typical use-case of retrieving connection strings from Azure or local configuration and the typical errors you might produce when you use this incorrectly. I found myself writing the same code very often so I encapsulated this into a simple set of fluent-ish extensions (I say “ish” because by technical definition of fluent, these aren’t self-referencing… yet). That said, I thought I’d share this code as it helps me get my apps started pretty quickly.

// Author: Tobin Titus <tobin.titus@gmail.com>
// Copyright (c) 2010 Tobin Titus
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.Configuration;

namespace AzureNinja.Storage
{
  public class Client
  {
    public const string DEFAULT_CONNECTION_STRING_NAME
          = "StorageConnectionString";
    static Client()
    {
       CloudStorageAccount.SetConfigurationSettingPublisher(
          (configName, configSettingPublisher) =>
          {
              var connectionString = RoleEnvironment.IsAvailable
                 ? RoleEnvironment.GetConfigurationSettingValue(configName)
                 : ConfigurationManager.AppSettings[configName];
               configSettingPublisher(connectionString);
          });
    }

    public static CloudStorageAccount FromConfig(
       string configSetting = DEFAULT_CONNECTION_STRING_NAME)
    {
        return CloudStorageAccount.FromConfigurationSetting(configSetting);
    }

    public static CloudStorageAccount FromString(string connectionString)
    {
       return CloudStorageAccount.Parse(connectionString);
    }
  }

  public static class CloudStorageClientHelpers
  {
    public static CloudBlobClient ForBlobs(this CloudStorageAccount account)
    {
       return account.CreateCloudBlobClient();
    }
    public static CloudQueueClient ForQueues(this CloudStorageAccount account)
    {
        return account.CreateCloudQueueClient();
    }
    public static CloudTableClient ForTables(this CloudStorageAccount account)
    {
        return account.CreateCloudTableClient();
    }
  }
}

You can then construct your requests for a CloudXxxClient as follows:

CloudBlobClient  client1 = Client.FromConfig().ForBlobs();
CloudQueueClient client2 = Client.FromConfig().ForQueues();
CloudTableClient client3 = Client.FromConfig().ForTables();

This uses “StorageConnectionString” as the default configuration key. And you can specify configuration key as well:

Client.FromConfig(“myConfigKey”).ForBlobs();

Furthermore, this allows you to concentrate on your calls to an otherwise fluent Azure API:

Client.FromConfig().ForBlobs().GetContainerReference(“myContainer”).Delete();

or

Client.FromConfig().ForBlobs()
     .GetContainerReference("myContainer").CreateIfNotExist();

Let me know if you have any questions or input.

CloudStorageAccount.SetConfigurationSettingPublisher

Those venturing into Windows Azure development for the first time may find themselves in a bit of a quandary when they try to devise a strategy for getting their storage account credentials. You dive into the Windows Azure APIs and determine that you must first get a reference to a CloudStorageAccount. You are all aglow when you find the “FromConfigurationSetting” method that takes a single string parameter named “settingName”. You assume that you can store your connection information in a configuration file, and call “FromConfigurationSetting” from your code to get dynamically load the connection information from the config file. However, like most of the Windows Azure documentation, it is very light on details and very heavy on profundity. The documentation for “FromConfigurationSetting” currently says:

Create a new instance of a CloudStorageAccount from a configuration setting.

That’s almost as helpful as “The Color property changes the color.” Notice that it isn’t specific about what configuration setting this comes from? The documentation is purposefully generic, but falls short of explaining why. So I’ve seen multiple questions in forums and blogs trying to figure out how this works. I’ve seen developers try to put the configuration setting in various places and make assumptions that simply providing the configuration path would get the desired result. Then they try to run the code and they get the following exception message:

InvalidOperationException was caught

SetConfigurationSettingPublisher needs to be called before FromConfigurationSetting can be used

Of course, this causes you to look up “SetConfigurationSettingPublisher” which also is a little light on details. It says:

Sets the global configuration setting publisher.

Which isn’t entirely clear. The remarks do add some details which are helpful, but don’t go as far as to help you understand what needs to be done – hence this blog post. So that was the long setup to a short answer.

The FromConfigurationSetting method makes no assumptions about where you are going to store your connection information. SetConfigurationSettingPublisher is your opportunity to determine how to acquire your Windows Azure connection information and from what source. The FromConfigurationSetting method executes the delegate passed to SetConfigurationSettingPublisher – which is why the error message says this method needs to be called first. The delegate that you configure should contain the logic specific to your application to retrieve the storage credentials. So essentially this is what happens:

  1. You call SetConfigurationSettingPublisher, passing in the logic to get connection string data from your custom source.
  2. You call FromConfigurationSetting, passing in a setting name that your delegate can use to differentiate from other configuration values.
  3. FromConfigurationSetting executes your delegate and sets up your environment to allow you to create valid CloudStorageAccount instances.

So, going back to a typical application, you want to store your configuration in a .config file and retrieve it at runtime when your Azure application runs. Here’s how you’d set that up. When your application starts up, you’ll want to configure your delegate using SetConfigurationSettingPublisher as follows:

CloudStorageAccount.SetConfigurationSettingPublisher(
  (configName, configSettingPublisher) =>
 {
    var connectionString = RoleEnvironment
         .GetConfigurationSettingValue(configName);
    configSettingPublisher(connectionString);
 }
);

If this is an ASP.NET application, you could call this in your Application_Start event in your global.asax.cs file. If this is a desktop application, you can set this in a static Constructor for your class or in your application startup code.

In this example, you are getting a configuration string the Windows Azure configuration file, and using the delegate to assign that string to the configuration setting publisher. This is great if you are executing in Windows Azure context all the time. But if you aren’t running your code in the Windows Azure context  (for instance, you are exercising your API from NUnit tests locally) this example will throw another exception:

SEHException was caught

External component has thrown an exception.

To solve this problem, you can set up the delegate to handle as many different environments as you wish. For example, the following code would handle two cases – inside a Windows Azure role instance, and in a local executable:

CloudStorageAccount.SetConfigurationSettingPublisher(
  (configName, configSettingPublisher) =>
  {
      var connectionString = RoleEnvironment.IsAvailable
          ? RoleEnvironment.GetConfigurationSettingValue(configName)
          : ConfigurationManager.AppSettings[configName];
      var connectionString = RoleEnvironment
          .GetConfigurationSettingValue(configName);
      configSettingPublisher(connectionString);
});

For your unit tests to work, just add an appSettings key to your configuration file:

<configuration>
 <appSettings>
  <add key="DataConnectionString"
    value="DefaultEndpointsProtocol=http;
              AccountName=<accountName>;AccountKey=<accountKey>;"/>
 </appSettings>
</configuration>

Note: Make sure to replace <accountName> and <accountKey> with your custom values.

In the context of your Windows Azure application, just make sure that you configure the same configuration key name there. In Visual Studio:

  1. Right click your Windows Azure role and choose Properties from the dropdown menu.
  2. Click on the Settings tab on the left.
  3. Click the Add Setting button in the button bar for the Settings tab.
  4. Type “DataConnectionString” in the Name column
  5. Change the Type drop down box to Connection String
  6. Click the “” (ellipsis) button in the right hand side of the Value column
  7. Configure your storage credentials using the values from the Windows Azure portal
  8. Click OK to the dialog
  9. Use the File | Save menu option to save your settings then close the settings tab in visual studio.

With this code, you should now be able to retrieve your connection string from configuration settings in a Windows Azure role and in a local application and retrieve a valid CloudStorageAccount instance using the following code:

var account = CloudStorageAccount
                   .FromConfigurationSetting("DataConnectionString");

Of course, you aren’t limited to these scenarios alone. Your SetConfigurationSettingPublisher delegate may retrieve your storage credentials from anywhere you choose – a database, a user prompt, etc. The choice is yours.

For those of you who need a quick and dirty way to get an CloudStorageAccount instance without all the hoops, you can simply pass your connection string in to the Parse or TryParse method.

var account = CloudStorageAccount.Parse(
   "DefaultEndpointsProtocol=http;" + 
   "AccountName=<accountName>;" + 
   "AccountKey=<accountKey>");

This should give you all the information you need to get a CloudStorageAccount instance and start accessing your Windows Azure storage.