Do Modules and dependent DLLs have to be in the .EXE directory?

Topics: Prism v4 - WPF 4
Oct 17, 2011 at 4:02 PM

Hi all,

I really have 2 questions.  Both are about loading modules, and seem like they should be simple questions.

I have a fairly mature WPF application using Prism and Unity where, to date, we were loading the modules from a particular directory, which requires references to the dependent DLLs in the shell application.  I would like to get rid of this dependency for a few reasons:

1.  I hate having the app build every time I press F5.

2.  We are creating a shell to be owned by another group, and therefore having references to our particular modules/dlls in a shell no longer owned by us is incorrect.

To this end, I have placed the module catalog loading in a .config file and loaded it from there (per prism config file loading approach).  But, this appears to still require the module dlls to live in the application directory, or at least have a copy there.  if not it bombs at startup with DLLs it can't find.

In addition, I want the shell to load up and then load the modules up after, to give the user the experience of rapid response of the shell popping up.  I tried to do this by loading the modules on demand by having a module controller listening for an event launched from the end of the shell startup.  Unfortunately, it sends the event and carries on, but the shell still doesn't come up completely until all the modules are loaded.  I suspect this is some assumption about event execution I have made which is wrong.

So, My 2 questions are:

1.  Can I load modules without having the dependent DLLs in the .EXE directory, and if so, how?

2.  Regardless of whether I can, what is the best way to get the shell to pop up and then have the modules load up directly after?

Any help is greatly appreciated.

Thanks,

Anthony.

Developer
Oct 17, 2011 at 6:08 PM

Hi Anthony,

There are several approaches that you can use to discover and initialize your modules without needing to have an explicit reference to them in the shell project. Based on my understanding of your scenario, discovering modules in a directory might be a useful approach to accomplish the requirements you describe. Using this approach the shell project does not need to reference the modules. Instead, your shell should only have a reference to the infrastructure project, which contains the required interfaces used by your shell and your modules. Then, in the bootstrapper, you will only need to create a DirectoryModuleCatalog specifying the directory in which your modules will be stored. This directory doesn't need to be the same directory of the shell project, however, you need to know where the modules will be stored or make your application obtain this location before creating the DirectoryModuleCatalog.

You can find more information about the different approaches regarding the loading and initialization of modules in the Chapter 4: Modular Application Development of the Prism documentation. Also, you can check the Modularity Quickstart for WPF included with the Prism guidance, which includes an example of the aforementioned approach among others.

Regarding the loading time of your shell project this could be happening, based on my understanding of your scenario, if the shell has a reference to your modules because the shell will need to load all the assemblies of each module before starting. You can try using an approach that does need to reference the modules in the shell (like for example the "discovering modules in directory" approach) and that load the modules on demand, so you could load the modules after your shell project is loaded.

I hope you find it useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Oct 17, 2011 at 7:03 PM

Thanks for the response.  I think you are saying exactly what I am doing.  I am sorry, maybe I didn't explain very well.

Having a directory approach is exactly what causes the need to have a reference in the application exe (the shell).  As soon as it tries to load up the modules in the bootstrapper it will not work without explicit reference in the shell to the dlls.  I have gotten around this by doing the .config method of loading the modules.  This means I don't need a reference in the exe.  But, I still need the DLLs in the exe directory.  Are you saying this is not true?  I have found no example to this effect, including the ones you referenced (which I have been through).  Maybe you are saying that it requires interfaces?

As for the loading time, it currently has not reference, and I am loading them on demand. I just think that I am having a bit of trouble figuring out the correct pattern to get the modules to load up after the shell is showing.  To be clear, I am doing the config method with them not being loaded at startup.

From the modular application development link you posted above:

"The registration and discovery mechanism you should use depends on what your application needs. Using a configuration file or XAML file allows your application to not require references to the modules. Using a directory can allow an application to discover modules without having to specify them in a file."

This is true, and it is why I am changing to the config file approach.  But, even without the references, when it tries to load the modules it gives me an errror running (can't find the DLL), unless at least a copy of it lives in the exe directory.  This is what I am trying to avoid.

As for loading the modules on demand, it can be quite easily done on a button click. I get that and have done that. I am looking for a decent pattern for getting the shell to load up the modules dynamically after it has rendered. I am just having trouble taking the buttton out of the equation, if that makes sense.

Thanks for any additional input.

Anthony.

Developer
Oct 18, 2011 at 10:06 PM

Hi Anthony,

The "discovering modules in a directory" approach does not require to have a reference to the modules and neither requires the dlls of the modules to be in the same directory that your shell application, your modules can be in any directory of your preference. I believe this makes this approach (based on my understanding of your scenario) useful to meet your requirements.

You can check the following sample application that uses the aforementioned approach:

In this sample application the bootstrapper loads two modules, one when the application starts and the other on demand, through the inspection of a directory. Note that the shell project does not have a reference to the aforementioned modules. To ensure that the dlls of the modules will be available in the specified directory, the projects have a build-post event (which is the same one used in the modularity quickstart) specified in its properties that copies the dlls to the specified directory (in this case, the "Modules" directory).

Also note that in this sample the shell windows loads before the modules and shows a small legend showing that the "when available" module is being loaded. The module that is loaded when available has a timer which sleeps the thread for 2 seconds to simulate that a heavy module is being loaded. As this is not specifically related to the directory discovery approach, the shell should appear before the initialization on any module regarding the approach used to locate the modules, so the modules should be initialized after the shell is rendered. Also, you can improve this by adding your custom logic to load the modules in a background thread.

As a side note, if you wish to use more that one approach to locate and load modules, you might find the class AggregateModuleCatalog provided with the modularity quickstart which seems to allow to combine multiple types of modules catalogs, including multiple DirectoryModuleCatalogs using different directories.

I hope you find it useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Oct 18, 2011 at 11:11 PM

Well, that all seems very concise.  Thank you very much for taking the time to stick with me. 

I have built and run the application, and it is very clear.  It is essentially exactly the same as what we are doing with some (obviously) distinct differences.  The catalog, the bootstrapper, the Module directory, and the on demand loading (which we are doing for one module IF the user has access) are nearly identical.  I think the one difference was that we were trying to keep the knowledge of where the module would load in the shell application and therefore had, in some round about way a reference to the modules.  From there, I found a few people (including the link you sent me to) that stated that you needed a reference in the shell application.  So, I sort of believed it.  In the end, I think that I need to remove some smarts from my shell.  It seems obvious that it needs to be dumber to be better.  I will attempt the changes when I am out of my meeting, but I have high hopes.

 

Again, Thank you very much for taking the time to help me out. 

Anthony.

Oct 22, 2014 at 10:58 PM
I know it's late, but I just fixed this in our project and want to clarify on this.

The reason you end up thinking that you need module DLLs in the Shell folder is that you haven't copied all module dependencies to the module folder (and by all I mean dependencies of dependencies, which are easy to miss). When the runtime wants to resolve these dependencies, it looks in the module folder but fails, so it then looks in the app's execution directory (the Shell's directory), fails as well, and then, in a somewhat misleading way, reports this last location in the error that it throws. This is why you end up thinking that you need the DLLs in the Shell's directory.

Again, in reality, all you need is to make sure all module DLLs are in the module folder. The only exception is: if you have a DLL that both the module and the Shell are using (the Microsoft.Practices DLLs are good examples of this), then you only need the one in the Shell directory; there's no need to have it in the module's folder as well. This is because, as I explained above, the runtime will also look for DLLs in the executing directory.