Supporting cloud and on-premises configuration with a single codebase.

I am frequently asked “How can I build an application on Azure, and use the Azure features (such as blobs, tables and queues), but still have the ability to deploy on premises without having two codestreams?”.

One answer is: you can still use Azure features from your on premises deployment. However, people are generally wary of too much tie-in to the platform, and want the option of deploying without the reliance on any Azure features.

Another answer is; Inversion of Control. If you use a dependency injection framework you can abstract away the implementation of the featues you want to use, and code against a common interface. This means you can work with a variety of underlying technologies, without your code being aware of that detail. The choice would be made by your configuration. I’ll show you how to to it using my favourite IoC framework; Spring.NET.

Start by creating an interface for each of the Azure features you want to use. For a queue, it could look like this:

public interface IQueue
{
  void Push(string message);
  string Pop();
}

Then create a concrete class that implements this feature for Azure:

public class AzureQueue : IQueue
{
  public AzureQueue(string connectionString)
  {
    this.Account = CloudStorageAccount.Parse(connectionString);
  }
  public CloudStorageAccount Account { get; private set; }
  public string QueueName { get; set; }
  public void Push(string message)
  {
    if (null == message) throw new ArgumentNullException("message");
    var queue = GetQueue();
    queue.AddMessage(new CloudQueueMessage(message));
  }
  public string Pop()
  {
    var queue = GetQueue();
    var message = queue.GetMessage();
    if (null == message)
    {
      return null;
    }
    queue.DeleteMessage(message);
    return message.AsString;
  }
  private CloudQueue GetQueue()
  {
    if (null == this.Account) throw new NullReferenceException("Account");
    if (null == this.QueueName) throw new NullReferenceException("QueueName");
    var queueClient = this.Account.CreateCloudQueueClient();
    var queue = queueClient.GetQueueReference(this.QueueName);
    return queue;
  }
}

Notice how the connection string is passed in to the constructor, and the queue name is a property. We don’t manually load anything from app settings.

Add the Spring.NET framework using nuget:

  Install-Package Spring.CodeConfig

Add a spring section to your config file, and configure your object:

<object id="queue" type="Two10.IoC.AzureQueue" singleton="true">
  <constructor-arg name="connectionString" value="UseDevelopmentStorage=true" />
  <property name="QueueName" value="test" />
</object>

Notice how the connection string and queue name are set in this configuration.

When you want an instance of the queue, you ask Spring for it:

static void Main(string[] args)
{
  IQueue queue = Create<IQueue>("queue");
  queue.Push("test message");
  string message = queue.Pop();
  Console.WriteLine(message);
  Console.ReadKey();
}
public static T Create<T>(string name) where T : class
{
  IApplicationContext context = ContextRegistry.GetContext();
  T obj = context.GetObject(name, typeof(T), null) as T;
  return obj;
}

Using a different queue provider is simply a matter of creating another implementation of IQueue, and modifying the configuration to return that instead of the Azure queue. You could have different configuration files for different builds, and Visual Studio will use the correct set of configuration depending on where the application is deployed.

The other real advantage with this approach is that it makes your code much more testable. By adding a mock for your interface, or a concrete class designed specifically for testing, you can write tests and that run in isolation from Azure.

Download an example project here, which also includes a MemoryQueue implementation.

Advertisements