November 2, 2011

Switching between the cloud and on-premise with StructureMap

Since I first started developing for the cloud, or specifically Windows Azure, one of my main objectives has always been to make the choice of environment just an implementation detail. This is the approach I wish Microsoft would also push, as I touched on in my post Windows Azure - My Experience so far.

The ability to easily switch between cloud and on-premise implementations is especially important to me as I don’t use the Azure emulator to develop Azure applications. Whilst the Azure emulator is pretty impressive, it is also incredibly slow. In fact I don’t even publish my web applications to Azure in the normal way. I use the Windows Azure Accelerator for Web Roles. To save money? No. For the simple reason that I get to web deploy updates in seconds rather than 20 minutes (the deployment scenario for Azure is by far its biggest downfall).

Taking this approach means that I have different implementations of infrastructure services used by my applications. For example, I have a “LocalStorageProvider” and an “AzureBlobStorageProvider”. If I’m using queues, I have a MSMQ implementation and one that uses Azure Queues.

To easily switch between groups of implementations we can make use of StructureMap (my favourite DI tool) Profiles.

To begin with we just declare our default implementations (non Azure) in the normal way:

For<ISiteCacheInvalidator>().Use<LocalSiteCacheInvalidator>();
For<IStorageProvider>().Use<LocalStorageProvider>();
For<IStorageProviderFactory>().Use<LocalStorageProviderFactory>();

To keep things separate I then create a StructureMap registry inside my Azure assembly that sets up the “Azure” profile:

public class AzureRegistry : Registry
{
    public AzureRegistry()
    {
        Profile("Azure", cfg =>
        {
            cfg.For<IStorageProvider>().Use<AzureBlobStorageProvider>();
            cfg.For<IStorageProviderFactory>().Use<AzureBlobStorageProviderFactory>();
        });           

        For<CloudStorageAccount>().Singleton().Use(ctx =>
        {
            CloudConfiguration.Initialize(ctx.GetInstance<IAppSettings>());
            return CloudConfiguration.GetStorageAccount();
        });
    }
}

Note that I’m not declaring the CloudStorageAccount inside the profile. Setting up dependencies inside a profile does not give you as much flexibility as normal (for example you can’t set the scope). In this case it doesn’t matter as I’ll only ever use CloudStorageAccount if I’m using the Azure implementations declared above.

In the main application we use StructureMap to scan and register registries in our assemblies:

cfg.Scan(scanner =>
{
	scanner.Assembly("Fabrik.Web");
	scanner.Assembly("Fabrik.Domain.Persistence");
	scanner.Assembly("Fabrik.Common.Azure");
	scanner.TheCallingAssembly();
	scanner.LookForRegistries();
});

(notice I’m using the same technique for my Persitence assembly to avoid having to reference NHibernate just for the purpose of registering dependencies).

At this point our Azure profile will be registered but not activated. To change the profile in code you would make a call to:

ObjectFactory.Container.SetDefaultsToProfile("Azure");

I used to wrap this in a call to RoleEnvironment.IsAvailable but found that often I wanted to run the application locally but use Azure blob storage or queues; in fact this is the way that we often test our applications. Therefore a config file approach would be much better.

Fortunately StructureMap can be completely configured using XML. I only want to use it for switching profiles as I prefer to use the fluent code-based configuration.

One way of doing this is to drop a StructureMap.config file in the root of your website. StructureMap will automatically find this. For example to set the profile we could just add a StructureMap.config file with the following contents:

<?xml version="1.0" encoding="UTF-8"?>
<StructureMap DefaultProfile="Azure">

</StructureMap>

Doing so would set the default implementations to those declared in the Azure profile. I opted to go for the web.config approach since it meant I could make use of Web.config transforms to set the profile (so I don’t have to remember to do this when I publish using Web Deploy).

In your web.config first declare the configuration section:

<section name="StructureMap" 
		 type="StructureMap.Configuration.StructureMapConfigurationSection,StructureMap"/>

By default we don’t declare any profile:

<StructureMap>
</StructureMap>

We then add the following to our Web.release.config:

<StructureMap DefaultProfile="Azure" xdt:Transform="Replace">   
</StructureMap>

This ensures that when ever I publish (using a Release build) the profile will be set to Azure.

We need to tell StructureMap to look in our application config file. To do this we set PullConfigurationFromAppConfig to true when we initialize the container:

public static void Initialize()
{
	ObjectFactory.Initialize(cfg =>
	{
		cfg.PullConfigurationFromAppConfig = true;

		// etc.
	});
}

The only time I have to manually set the profile is on our dev server as we often publish a release version (using Web Deploy) but want to run our on-premise implementations. Either way, it’s a simple case of changing a config file.

So if you’re like me and want the benefits of Azure without any constraints on your dev environment, this should make your deployment process much easier.

© 2022 Ben Foster