I’m working on a project where we are using the Composite Application Library from Microsoft’s patterns & practices team. You can read the official documentation on that site and on MSDN for all the details, but basically the CAL allows you to build applications using totally decoupled modular components – or “modules” in CAL vernacular. These modules are discovered at runtime and are registered in the CAL container, which then handles each modules’ loading, showing, unloading, etc. (I’m greatly simplifying here).
To enable runtime module discovery, you can pick between one of four different “cataloging” methods:
- Populate from code
- Populate from XAML
- Populate from a configuration file
- Populate from a directory
The fourth one, populating from a directory, is what we wanted to use. This method of cataloging allows you to drop modules into a directory and have them picked up by the CAL. Essentially, it examines all assemblies in the directory and looks for types decorated with the ModuleAttribute attribute.
The CAL’s implementation of this directory cataloging only allows for a single directory. It does this through the DirectoryModuleCatalog catalog. As taken from the CAL’s documentation, the following example will configure your application to search in a Modules subdirectory for all modules:
1: protected override IModuleCatalog GetModuleCatalog()
2: {
3: return new DirectoryModuleCatalog() {ModulePath = @".\Modules"};
4: }
Very cool!! But… we need to search through multiple directories – not just a single directory.
Long story short, I was able to subclass the DirectoryModuleCatalog to create a new directory-based catalog that can search as many directories as you want to give it. Now, you might laugh at my new catalog, but it does work!! Here it is:
1: /// <summary>
2: /// Allows our shell to probe multiple directories for module assemblies
3: /// </summary>
4: public class MultipleDirectoryModuleCatalog : DirectoryModuleCatalog
5: {
6: private readonly IList<string> _pathsToProbe;
7:
8: /// <summary>
9: /// Initializes a new instance of the MultipleDirectoryModuleCatalog class.
10: /// </summary>
11: /// <param name="pathsToProbe">An IList of paths to probe for modules.</param>
12: public MultipleDirectoryModuleCatalog(IList<string> pathsToProbe)
13: {
14: _pathsToProbe = pathsToProbe;
15: }
16:
17: /// <summary>
18: /// Provides multiple-path loading of modules over the default <see cref="DirectoryModuleCatalog.InnerLoad"/> method.
19: /// </summary>
20: protected override void InnerLoad()
21: {
22: foreach (string path in _pathsToProbe)
23: {
24: ModulePath = path;
25: base.InnerLoad();
26: }
27: }
28: }
All you need to do is provide an IList<string> of paths – that’s it! So, to update the CAL’s sample:
1: protected override IModuleCatalog GetModuleCatalog()
2: {
3: IList<string> pathsToProbe = GetPathsToProbe();
4: return new MultipleDirectoryModuleCatalog(pathsToProbe);
5: }