Today we will see the modularity concept of Prism. Probably the best part of it, as it will allow us to build a real plug-and-play application where the main Shell wonâ€™t know anything about the modules.
Discover and load the module.
What does it mean? As we saw in the previous article, we have declared a reference in our Shell for the hello world module. In this way we force the Shell to be compiled including in the shell project a reference to the Hello World module. Fine, but what happen if we want to replace this module with a new version? We need to change the reference in the project and recompile it â€¦ Pretty ugly for a modular application doesnâ€™t it?
The basic concept in Prism is that we can discover on fly the available modules and load them â€¦ This is the workflow process of discovering and loading a module in Prism.
There are different ways to load a module. As we saw in the previous article, the easiest way is to add a direct reference to the module in the Shell and load it in the bootstrapper:
1: ModuleCatalog catalog = new ModuleCatalog()2: .AddModule(typeof(HelloWorldModule.HelloWorldModule));
The second way is to add the module reference in the app.config and REMOVE the code in the bootstrapper. In this way we wonâ€™t need to recompile the module each time we will run the application in Visual Studio and we wonâ€™t need a direct reference to it. Letâ€™s see the code below. I have a added an app.config file in my shell project:1: <?xml version="1.0" encoding="utf-8" ?>2: <configuration>3: <configSections>4: <section name="modules"5: type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection, Microsoft.Practices.Composite"/>6: </configSections>7: <modules>8: <module9: assemblyFile="Modules/HelloWorldModule.dll"10: moduleType="HelloWorldModule.HelloWorldModule, HelloWorldModule"11: moduleName="HelloWorldModule"/>12: </modules>13: </configuration>
I am using the composite section in the app.config file to load a specific module. Now, in order to make this â€˜runnableâ€™ we need to:
- remove the reference in the Shell project
- clean-up the code in the bootstrapper that loads the module
The shell project will use this code now to load the Module catalog:
1: ModuleCatalog catalog = new ConfigurationModuleCatalog();
As you can see we are telling to Prism to look in the app.config and load the modules available there. In order to make the module available in the modules folder inside the bin folder of the shell you can play with MSBuild or a post-event action in VS. I copied this code from MSDN and added to the post event build action in the HelloWorldModule project properties:1: xcopy "$(TargetDir)*.*"2: "$(SolutionDir)Shell\bin\$(ConfigurationName)\Modules\" /Y
Pretty cool! We can now work with our modules without breaking any change in the Shell project, and trust me, when you work on a team, this happens every day â€¦
Additional configuration options.
Of course the game is not done yet. We have a lot of options that we can configure in the app config in order to load modules on fly and to add dependencies from other modules. For example, letâ€™s say that Outlook canâ€™t open a view if the ribbon is not loaded, but the ribbon is on another module â€¦
Load on demand
We can specify, for example, that we want to load on demand (by request) a specific module that we donâ€™t know. Pretty cool as this is how should work a real modular application. In order to do this we donâ€™t need anything more that this tag in the app.config:1: <module2: assemblyFile="Modules/HelloWorld.dll"3: moduleType="HelloWorld, HelloWorld"4: moduleName="HelloWorld"5: InitializeMode="OnDemand"/>
Now that we setup the module to load â€œonDemandâ€ the module wonâ€™t be load in memory until we will instruct Prism to do that. This is a real plug and play concept, because without any dependencies we can load on demand part of our UI during the program execution. In Windows Form this canâ€™t simply be done!1: moduleManager.LoadModule("HelloWorld");
There you go, in a simple call from any view we can ask for a specific module. The initialize method of the module will be call and our UI will receive the â€˜defaultâ€™ view of that module, injected in the shell or in another module â€¦ there are no limitations at all.
Now we are ready to build the first cool module of our app, the main Ribbon bar.