If you develop WPF applications with Prism, then you are probably already aware of the many ways in which you can load a module. Loading a module starts with what is called a ModuleCatalog. You can’t load a module unless it has been added to a ModuleCatalog. Once the module has been added to a ModuleCatalog, Prism will then take care of loading the module assembly for you. Prism even comes with a handful of module catalogs to give you flexibility in how you register your modules with your Prism application. You can populate a module catalog from code, from XAML, with XML in an app.config, or from a directory. Heck, you can even use a combination of all these options to populate your module catalog.
When I am giving a Prism talk at a public event or an internal lunch and learn at a company, I am sure to explain all the different ways of loading your modules and which catalog to use. This is about the time where the questions really start getting interesting. Of these questions, the most common is about the DirectoryModuleCatalog. This particular catalog allows you to specify a folder path to load your modules from. Now the interesting question… “but, what happens when a new module assembly is dropped into the folder? Will it automatically be loaded into the app while it is running?” That is a great question, and the answer is NO. The DirectoryModuleCatalog does a one time scan of the directory and then loads all the modules that it finds. If you drop a new module assembly into the directory, it will not be loaded until the application is restarted. Now the follow-up question… “well, is it possible to dynamically discover the modules and load them from the directory as well?” Answer; well of course it is. If you’re using MEF, it’s easy. If you’re using a container such as Unity, you will need to write the code to handle it yourself. “Well, we don’t use MEF, so can you show us how?” This is where my reply is always the same, “a simple web search (Google or Bing) should help you find what you are looking for”.
Well, it turns out, that’s not the case. It seems that no one has blogged about or shared any code that handles the dynamic discovery and loading of modules using a DI container such as Unity. Not that I could find, nor anyone who is asking me to show them could find. Which leads me to this post. I am going to show you an approach that I have used to support such a scenario. I am actually going to give you two approaches. One is the “Quick and Dirty” way. Basically, I will throw together the simplest sample to achieve the goal. Then I will show you “A Better Way” in which we will encapsulate this functionality into a custom ModuleCatalog that will handle everything for us.
Here is the Prism app we are using to test our code.
It’s a Prism application that contains a Shell with a single region and one module that contains a single view. When the module is loaded properly, this will be the final result.
Quick and Dirty
The “Quick and Dirty” way, is well…. quick and dirty. First we need to determine what mechanism we are going to use to detect when a new module assembly has been added to our modules directory. This is a no brainer. We will be using the FileSystemWatcher class. The FileSystemWatcher monitors a given directory for changes and notifies us via events that a change has occurred. Such as a file being added to the directory. Let’s create an instance of this class in our Bootstrapper constructor and listen for it’s Created event.
Notice that in the constructor of the FileSystemWatcher, it takes the location of the directory we want to monitor, as well as a second parameter which allows us to specify a filter. In this case we only care about DLLs. We also need to set the FileSystemWatcher.EnableRaisingEvents = true in order to start the monitoring of the directory. Now anytime a new DLL is added to our directory, our event handler will execute. Time to check out our event handler
This code takes the newly added assembly and loads it into our application. Next we search the assembly for all classes that implement IModule, which is the interface that specifics it represents a Prism module. Next we loop through all the found modules and add them to the ModuleCatalog. We have to do this because we can’t load a module that is not registered in the module catalog. Now we use the IModuleManager to load the module using the Dispatcher. We have to use the Dispatcher because the FileSystemWatcher.Created event listens on a separate thread, and we need to load the modules on the main thread. The Dispatchers allows us to push the modules from a different thread to the main thread. Now lets go ahead and run the application and copy the ModuleA.DLL into the application’s Modules folder directory and see what happens.
Run the application and open the application’s /Modules directory location and the ModuleA’s Bin/Debug/ModuleA.dll file location. As you can see, there are no modules loaded for the application and the Prism application is showing an empty shell.
Now, copy the ModuleA.dll from the module’s Bin/Debug directory into the Prism application’s /Modules directory. As soon as the copy operation has completed, the ModuleA.dll assembly is loaded, and the ModuleAView is injected into the Shell;s region. All while the app is running. No need to shutdown and restart the app.
So that was the quick and dirty way. Now let’s look at how we can make a custom ModuleCatalog that will not only load modules from a directory just like the default Prism DirectoryModuleCatalog does, but also allow us to monitor the directory for newly added modules at runtime.
A Better Way
We just saw how, with a few lines of code, we could dynamically discover and load modules. Now, let’s create a custom ModuleCatalog class that will not only register and load existing modules from a directory, but also monitor that same directory for newly added modules at runtime. This class should be a little more stable and do proper app domain and evidence creations and in memory reflection without loading the assemblies into the main app domain until actually needed. We are also going to remove the dependency on the Dispatcher and instead use the SynchronizationContext class. I am not going to walk through all of the code. I am just going to provide the code and you can read through it.
This is how you would use the newly created DynamicDirectoryModuleCatalog in our Prism Bootstrapper.
You might not know this, but you can even have multiple instances of your Prism application monitor the same directory and load the same modules.
Pretty cool huh? You can now dynamically discover and load your Prism modules at runtime.