Deploying applications to Azure requires a change in the way of thinking about configuration. When roles can be spun-up at any time, the configuration settings will be what the deployment package contains. This means changing configuration within a role will most likely lose those changes when Azure moves a role, a role crashes or you add another role. The key is to make sure that the deployment package is up to date. By using the abstracts below, a developer can write code that works inside and outside of Azure.

A Windows Azure project contains configuration files for each environment called ServiceConfiguration.*.cscfg. You can create more than the default provided, which are Local and Cloud. Keeping the Azure Storage connection string and other settings in these files allows for greater portability.

By setting the CloudStorageAccount‘s publisher, the developer can read configuration values differently than strictly using ConfigurationManager. Under a Role’s project properties, browse to the Settings tab. For this example, you’ll want to click “Add Setting” and specify the details for Name and Type as below. The DataConnection setting will be used to store the connection string for Azure Storage.

For the Value, notice the ellipse button. It will provide a popup with the following.

When using the storage emulator, the Value will be set to “UseDevelopmentStorage=true”. The focus of this post is leave the configuration management in these settings as much as possible. This helps to allow the code to remain unchanged when moving between environments. There is a Service Configuration dropdown on the Settings tab that should be changed and the appropriate values specified for each scenario. For example, specify use of development storage for Local and specify the account credentials for Cloud.

Please note that the code shown below can be refactored to live in different places. It doesn’t have to be put into the global.asax or in each Controller for MVC projects. Using WebActivator, base classes and helper classes are worth considering.

Setting the configuration publisher within the Application_Start method in the global.asax file is the first action to take.

		protected void Application_Start()
		{
			AreaRegistration.RegisterAllAreas();

			RegisterGlobalFilters(GlobalFilters.Filters);
			RegisterRoutes(RouteTable.Routes);

			BundleTable.Bundles.RegisterTemplateBundles();

			CloudStorageAccount.SetConfigurationSettingPublisher(
				(configurationName, configurationSettingPublisher) =>
					configurationSettingPublisher(RoleEnvironment.GetConfigurationSettingValue(configurationName)));
		}

As the code self documents, the SetConfigurationSettingPublisher method takes a lambda expression as an argument. The configurationName variable is of type string and the configurationSettingPublisher variable is of type System.Func<string, bool>.

In case you don’t have a tool to automatically import using statements, the following are required.

	using Microsoft.WindowsAzure;
	using Microsoft.WindowsAzure.ServiceRuntime;

Before moving on, I want to point out that I’m using a static constants class to keep hard-coded strings in one place. This hard-coded string bridges the gap between code and the settings, but the value is what we are concerned about changing.

	public static class ConfigurationConstants
	{
		public const string DataConnection = @"DataConnection";
	}

Now that the wiring up of the Storage configuration is done, we need to consume it. For this example, let us use a Controller class from an ASP.NET MVC4 project that is specified as a WebRole. A few steps are needed to get access to the TableServiceContext.

	using System.Web.Mvc;

	using Microsoft.WindowsAzure;
	using Microsoft.WindowsAzure.ServiceRuntime;
	using Microsoft.WindowsAzure.StorageClient;

	public class HomeController : Controller
	{
		private readonly CloudStorageAccount cloudStorageAccount;
		private readonly CloudTableClient cloudTableClient;
		private readonly TableServiceContext tableServiceContext;

		public HomeController()
		{
			this.cloudStorageAccount = CloudStorageAccount.FromConfigurationSetting(ConfigurationConstants.DataConnection);

			this.cloudTableClient = new CloudTableClient(this.cloudStorageAccount.TableEndpoint.AbsoluteUri, this.cloudStorageAccount.Credentials);

			this.tableServiceContext = this.cloudTableClient.GetDataServiceContext();

			string someOtherSetting = RoleEnvironment.GetConfigurationSettingValue(ConfigurationConstants.SomeOtherSetting);
		}
	}

Inside the constructor, the first statement is retrieving the configuration setting for the data connection. This allows changing the setting from the project level based on the service configuration (Debug, Cloud, etc.) and not having to change any code when switching environments. If the CloudStorageAccount.DevelopmentStorageAccount option is used instead of the FromConfigurationSetting method, it is essentially using a hard-coded value.

The second statement is creating a CloudTableClient, which can be replaced with a CloudQueueClient or CloudBlobClient. The constructor for the CloudTableClient is taking in a Uri and a StorageCredentials as arguments. By using the overload for the Uri and using an AbsoluteUri for the value, it avoids complications with changing Endpoints (Http, Https, TCP).

From here, the third statement is simply gaining access to the TableServiceClient. The last statement is showing how to read a setting that isn’t going through the CloudStorageAccount.

You’ll most likely want to have your table name(s) specified in configuration or use whatever mechanism works for your business case. Also, don’t forget to properly check if the table exists before using it. There are methods on the CloudTableClient for doing that type of management.

We all want to avoid hard-coding, so whatever approach you take make sure it’s not going to limit you or cause problems later in the application’s life.

Comments are closed.