Posts Tagged configuration

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

Configuration Files and Windows Azure

Last week I posted a short article on how easy it is to move an ASP.NET Web Application to the cloud… and it is extremely easy, as long as you don’t have any data, configuration settings, 3rd party libraries, or other issues getting in the way! Actually, all kidding aside, it is pretty easy as long as you understand what’s different and what’s similar when you’re running in the cloud. With a little effort, you should be able to come up with a strategy that doesn’t force you to re-engineer your application; you might even be able to keep your Web application in a state that can be deployed to the Web or to the cloud without any configuration changes!

In this post I’d like to address configuration. If you’re an ASP.NET Web developer, you already know all about web.config, and you probably use it all the time to store configuration settings for your application. Let’s assume you want to store a simple message in configuration; your web.config file would contain the following:

<appSettings>
   <add key="messageText" value="Hello, ASP.NET!"/>
</appSettings>

Then you could write some application code that retrieves the value (in this case, displaying it on the Web page using an ASP.NET Label control):

message.Text = WebConfigurationManager.AppSettings["messageText"];

The good news is that Web applications running in Windows Azure support web.config so this code will work without any modifications whatsoever. The bad news is that when you deploy an Azure application, the web.config file gets packaged up along with the rest of the Web application components in a .csx file. This sort of defeats the purpose of putting your message in a configuration file, yes? If you didn’t need the ability to change the message without recompiling your application you could have just placed the message text directly into your code. So web.config is a great place for application settings unless you’re app is in the cloud…

Ah, but Windows Azure does support the idea of a configuration file – it goes by the name ServiceConfiguration.cscfg and it gets deployed separately from the .csx package. And, you can add your own custom settings to it, just like web.config. It takes a bit more effort, since you must first define the setting in ServiceDefinition.csdef:

<ConfigurationSettings>
   <Setting name="messageText"/>
</ConfigurationSettings>

…and then set the actual value in ServiceConfiguration.cscfg:

<ConfigurationSettings>
   <Setting name="messageText" value="Hello, Azure!"/>
</ConfigurationSettings>

Once you’ve done that, you can retrieve the value quite easily:

message.Text = RoleManager.GetConfigurationSetting("messageText");

If you’re moving your application into the cloud and you’re “not looking back,” it may make sense to move your settings into the .cscfg file and use that exclusive of web.config. But what about building an application that can be deployed in AND out of the cloud?

Fortunately, it is not difficult to determine at runtime whether you are running in or out of the cloud and retrieve configuration settings as appropriate. In the following code, note how we can check the RoleManager.IsRoleManagerRunning property:

if (RoleManager.IsRoleManagerRunning)
{
   // we're in the cloud
   message.Text = RoleManager.GetConfigurationSetting("messageText");
}
else if (System.Web.HttpContext.Current != null)
{
   // we're NOT in the cloud, but we're still in a Web application
   message.Text = WebConfigurationManager.AppSettings["messageText"];
}
else
{
   // not in the cloud, not in the web... desktop app maybe?
   message.Text = ConfigurationManager.AppSettings["messageText"];
}

As you can see, we’ll get the value stored in .cscfg if we’re running in the fabric (the cloud), we get the one from web.config if we’re a “regular” ASP.NET Web application and we can even fall back to the standard .NET Configuration manager.

One more thing – checking RoleManager.IsRoleManagerRunning all the time will surely get tedious if you have a lot of settings to retrieve. You may want to encapsulate the settings retrieval into a reusable component, perhaps similar to the following:

public class SettingsManager
{
   private static Settings _settings = new Settings();
   public static Settings Settings
   {
      get
      {
         return _settings;
      }
   }
}
public class Settings
{
   public string this[string key]
   {
      get
      {
         if (RoleManager.IsRoleManagerRunning)
         {
            return RoleManager.GetConfigurationSetting(key);
         }
         else if (System.Web.HttpContext.Current != null)
         {
            return WebConfigurationManager.AppSettings[key];
         }
         return string.Empty;
      }
   }
}

You can find a much more comprehensive example (one that also deals with logging) in the HelloFabric sample that ships with the Windows Azure SDK.

, ,

6 Comments