I wrote an article several months ago with an overview of how a dependency injection framework can demystify the process of standing up and configuring a new application. Not only can you eliminate writing out copious custom configuration code, you can also decouple configuration from your core application logic (if you’re really a glutton for punishment, you can find the tripe I wrote here).
I recently solved a problem I faced, where I wanted to be able to store modules for an application outside of the normal configuration space, and hoped to be able to leverage Unity to do it.
That’s right, another Unity post…
The Use Case
Specifically, this would be most useful if you want to decouple the specifics of what your application does into a separate installation and/or management system. To provide a really, really simplified, and perhaps difficult to find in the real world, example — imagine you have an application that processes work files, where you can configure any number of worker threads for any number of directories:
- Worker 1 pulls files from directory A, transforms information into database objects and runs insertions.
- Worker 2 pulls files from directory B, transforms information into SOAP data and posts to a service.
Now, you *could* dump information about each thread into the application configuration file. Then your IT people will hate you. So if you are OK with that as your status quo, feel free to stop reading. However, if you want to make an application distributable and easy to install and maintain, this may be of interest. Instead of coupling the specifics of what Workers 1 and 2 are doing into the application configuration, it would be better to envision them as individually configured modules, that are loaded from a location outside of your application directory dynamically at runtime. You can update your application without fear of overwriting configuration. You can also update your modules without making code changes. You can even control distribution of your modules, pushing them out to multiple locations to meet horizontal scaling demands.
This solution is kinda alright.
It turns out there is a very simple way to append one Unity configuration to another. The UnityConfigurationSection
can configure a Unity container with the data it stores. The only issue is the code that deserializes the configuration XML is protected, so you have to inherit it in your own type:
public class UnityModuleSection : UnityConfigurationSection
{
public UnityModuleSection(XmlReader reader)
{
reader.ReadStartElement();
this.DeserializeSection(reader);
}
}
With that available, appending a configuration becomes very easy. You can store another Unity configuration in its own .config file, which would be the path argument in the following extension method:
public static class UnityModuleExtensions
{
public static void AppendConfiguration(this IUnityContainer container, string path, string containerName)
{
using (var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
using (var reader = new XmlTextReader(stream)) {
var newConfig = new UnityModuleSection(reader);
newConfig.Configure(container, containerName);
}
}
}
}
(Note: I like to explicitly specify container names. You don’t have to, but you’ll need to know the name of your existing container and use that).
It’s really that easy. When you call .Configure
on an existing Unity container, anything that has been set is fully preserved, so long as there are no naming conflicts. Anything regarded as new will be added to what is already there.
There are a few caveats with this approach, as it is a bit of a hack and comes with the expected imperfections:
- This is taking advantage of what could be unintended functionality of the Unity configuration classes. There are no guarantees that this will continue to be available in future revisions of the product.
- By using this, you are tightly coupled to the entire application configuration syntax if you make any “module” configurations to be loaded at runtime. There is some upside to this, in that it is well-maintained standard, and you could potentially utilize 3rd party Unity configuration tools to maintain your configuration modules. However, you are also stuck rewriting the same namespaces and aliases over and over, and any type that must be resolved for injection must be fully specified in your module config.
I think I could resolve these limitations by providing a simplified schema that mimics what is available in Unity configuration, but would be able to utilize existing aliases, type mappings, instances, namespaces, etc. However, in the meantime, this has proven very useful.
In closing, I hope someone finds a good use for this as I have, and even improves upon my hack. Happy coding!