The next step in the Generic Worker is to use IoC and DI and fully decouple workerrole plumbing from the actual functionality. Using IoC also makes it easy to configure your workerrole(s) and e.g. dynamically add/remove aspects (AOP) to your applications. The power of AOP is weaving the mixed behaviors together. Apply different aspects to change behavior and functionality of classes without using techniques like inheritance.
The first step i take is to extend the basic Unity behaviour and write my own Resolve method to resolve types not loaded in my appdomain but actual types that reside in my assembly blob storage. Follow the next steps to accomplish completely uncoupled software that makes use of Blob Storage and Unity.
1. Create a classlibrary that contains the interfaces for your classes to be loosely coupled.
public interface ICalculation
{
int Addition(int a, int b);
}
2. Create a classlibary that has a concrete implementation of this interface. This class implements one or more of the interfaces you defined in the classlibrary you created in step 1.
public class DefaultCalculation : ICalculation
{
public int Addition(int a, int b)
{
return a + b;
}
}
3. Build your classlibrary containing the implementation. Take the assembly and upload it somewhere in your Azure Blob-o-sphere Storage. See this screenshot.
You can see the assembly is in my assemblyline storage account and assemblies container.
4. Extent the Unity container with your own method that Resolves in a different way. Not trying to find implementations somewhere in current appdomain but actually take assemblies from Blobstorage and load them. This code runs in my workerrole that's supposed to be awfully generic.
using (IUnityContainer container = new UnityContainer())
{
container.ResolveFromBlobStorage
}
I will update my next code with a fancy LINQ query but no time right now.
public static void ResolveFromBlobStorage<T>(this IUnityContainer container) where T : class
{
CloudStorageAccount csa = new CloudStorageAccount(
new StorageCredentialsAccountAndKey("assemblyline", "here goes your key"),
true);
//take the assemblies from Blob Storage
CloudBlobContainer cbc = csa.CreateCloudBlobClient().GetContainerReference("assemblies");
var assemblies = (from blobs in cbc.ListBlobs()
select blobs);
foreach (IListBlobItem assembly in assemblies)
{
byte[] byteStream = cbc.GetBlobReference(assembly.Uri.AbsoluteUri).DownloadByteArray();
//load the assembly from blob into currentdomain.
AppDomain.CurrentDomain.Load(byteStream);
foreach (Assembly currentAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in currentAssembly.GetTypes())
{
if (!typeof(T).IsAssignableFrom(type) || type.IsInterface)
continue;
container.RegisterType(typeof(T), type, new ContainerControlledLifetimeManager());
}
}
}
After this code the Unity container is extended with the method ResolveFromBlobStorage.
Step 5 and final:
using (IUnityContainer container = new UnityContainer())
{
container.ResolveFromBlobStorage<ICalculation>();
ICalculation math = container.Resolve<ICalculation>();
Console.WriteLine(String.Format("adding 2 and 3 makes : {0}", math.Addition(2 , 3).ToString()));
}
The ResolveFromBlobStorage method makes it possible to have concrete implementations outside of my solution somewhere and stuffed away in blobstorage. I only need the interface that's it!
Happy programming!