Posts Tagged setconfigurationsettingpublisher

SetConfigurationSettingPublisher demystified

I am often asked by students about the purpose of Azure’s CloudStorageAccount.SetConfigurationSettingPublisher method, particularly when they experience the infamous “SetConfigurationSettingPublisher needs to be called before FromConfigurationSetting can be used” error.

I suppose part of it is the potentially unfamiliar syntax, so let’s start there. You will usually find SetConfigurationPublisher called in code that looks similar to the following:

CloudStorageAccount.SetConfigurationSettingPublisher((configName,
                                                      configSettingPublisher) =>
{
    string configValue = RoleEnvironment.GetConfigurationSettingValue(configName);
    configSettingPublisher(configValue);
});

In a nutshell, you’re invoking a method that expects a method that takes a method as a parameter. Confused? No worries – it becomes clearer once you unravel the lambda expression.

First, note that the SetConfigurationSettingPublisher method expects a single parameter, of type Action<string,Func<string,bool>>. Instead of using the lambda expression, we could simply define a matching method as follows:

private void MySettingPublisher(string configName,
                                Func<string, bool> configSettingPublisher) {
}

Then the call to SetConfigurationSettingPublisher becomes the following:

CloudStorageAccount.SetConfigurationSettingPublisher(MySettingPublisher);

Now, when a call is made to retrieve settings from configuration, Azure will invoke our MySettingPublisher method. So far so good, but it won’t work yet because our method doesn’t actually do anything. If you look at the parameters that are passed to our method, you will notice that we receive a string (called configName) and a Func<string,bool> called configSettingPublisher. In other words, Azure will give us the name of the configuration setting that is being retrieved as well as a method that expects a string and returns a Boolean. We just need to call that method once we’ve figured out what the value for the setting should be. So, a few lines of implementation are all it takes to complete our code:

private void MySettingPublisher (string configName,
                                 Func<string, bool> configSettingPublisher)
{
   string configValue = RoleEnvironment.GetConfigurationSettingValue(configName);
   configSettingPublisher(configValue);
}

When you use a method such as CloudStorageAccount.FromConfigurationSetting, Azure looks for a setting publisher. Thanks to an earlier call to SetConfigurationSettingPublisher, it finds your MySettingPublisher method which it dutifully invokes. Your code gets the actual value from configuration (using RoleEnvironment.GetConfigurationSettingValue) and invokes the method Azure provided with the Func<string, bool> parameter.

But why all this back-and-forth between Azure and your code? Shouldn’t CloudStorageAccount.FromConfigurationSetting know that you want to grab the setting out of ServiceConfiguration.cscfg and just take care of it for you?

It turns out that being able to set your own “setting publisher” has code reusability benefits. The most likely scenario is building a Web application that may or may not run in Azure. No Azure, no Service Configuration.cscfg file so you might place the setting in the <appSettings> section of Web.config:

<configuration>
  <appSettings>
    <add key="MyConnectionString" value="UseDevelopmentStorage=true" />
  </appSettings>
</configuration>

Now, let’s modify our MySettingPublisher method as follows:

private void MySettingPublisher(string configName,
                                Func<string, bool> configSettingPublisher)
{
  var configValue = RoleEnvironment.IsAvailable ?
       RoleEnvironment.GetConfigurationSettingValue(configName) :
       System.Web.Configuration.WebConfigurationManager.AppSettings[configName];
  configSettingPublisher(configValue);
}

With this in place we can run our Web application outside Azure and it still works, it just uses Web.config instead of ServiceConfiguration.cscfg.

By the way, as Steve Marx points out, if you are building an Azure-specific solution and would rather not worry about all this “setting publisher” business, you could simply use the following to initialize your storage account:

string configValue = RoleEnvironment.GetConfigurationSettingValue("MyConnectionString");
CloudStorageAccount account = CloudStorageAccount.Parse(configValue);

 

Sample code here!

, ,

No Comments