Modules Loaded on Demand Preventing Application Exit?

Topics: Prism v2 - WPF 3.5
Jun 12, 2009 at 3:48 PM

Hi all,

I'm evaluating Composite WPF by developing a test application. I would like to load some modules on demand, from a module catalog populated by a configuration file. However after implementing this behavior, my application does not exit. When I close the main window, the window disappears, but the application is still running (Visual Studio is still in debugging mode).

My App.config looks like:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <configSections>
      <section name="modules" type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection, Microsoft.Practices.Composite" />
   </configSections>
   <modules>
      <module assemblyFile="TestApp.Modules.AModule.dll" moduleType="TestApp.Modules.AModule.AModule, TestApp.Modules.AModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="AModule" startupLoaded="false">
         <dependencies>
            <dependency moduleName="BModule" />
         </dependencies>
      </module>
      <module assemblyFile="TestApp.Modules.BModule.dll" moduleType="TestApp.Modules.BModule.BModule, TestApp.Modules.BModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="BModule" startupLoaded="false" />
   </modules>
</configuration>

 

My bootstrapper looks like this:

 

public class Bootstrapper : UnityBootstrapper
{
   protected override DependencyObject CreateShell()
   {
      Shell shell = this.Container.Resolve<Shell>();
      shell.Show();
      return shell;
   }

   protected override IModuleCatalog GetModuleCatalog()
   {
      ModuleCatalog catalog = new ConfigurationModuleCatalog();
      return catalog;
   }

   protected override void InitializeModules()
   {
      base.InitializeModules();

      Shell shell = this.Container.Resolve<Shell>();
      IModuleManager module_manager = Container.Resolve<ModuleManager>();
      shell.InitializeModules(module_manager);

      return;
   }
}

 

 

My shell looks like this:

public partial class Shell : Window
{
   public Shell()
   {
      InitializeComponent();
      return;
   }

   public void InitializeModules(IModuleManager moduleManager)
   {
      moduleManager.LoadModule("BModule");
      moduleManager.LoadModule("AModule");
      return;
   }
}

 

Any ideas on what the problem might be?

Jun 12, 2009 at 6:14 PM

Hi emddudley,

 

I was able to reproduce the error you mention (Thanks for posting the code) and found the issue.

The problem is in the following code (the line in bold and commented):

protected override void InitializeModules()

{

    base.InitializeModules();

 

    Shell shell = this.Container.Resolve<Shell>(); // This line creates a new instance of the shell

    IModuleManager module_manager = Container.Resolve<ModuleManager>();

    shell.InitializeModules(module_manager);

 

    return;

}

 

As you are creating a new instance of the shell (but not showing it), when you close the visible instance of the shell, the application keeps running.

 

Workarround

A possible and simple workaround is not to use the shell in the InitializeModules method moving the Shell.InitializeModules method to the Bootstrapper as follows:

               

      public class Bootstrapper : UnityBootstrapper

{

            protected override DependencyObject CreateShell()

            {

                ...

            }

 

            protected override IModuleCatalog GetModuleCatalog()

            {

                  ...

            }

 

            protected override void InitializeModules()

            {

                base.InitializeModules();

 

                //Shell shell = this.Container.Resolve<Shell>(); // This line creates a new instance of the shell

                IModuleManager module_manager = Container.Resolve<ModuleManager>();

                this.InitializeModules(module_manager);

 

                return;

            }

 

            public void InitializeModules(IModuleManager moduleManager)

            {

                moduleManager.LoadModule("BModule");

                moduleManager.LoadModule("AModule");

                return;

            }

        }

 

If your scenario forces you to load the modules in the Shell class, you can both:

1.       Keep a reference to the shell created in the CreateShell Method as a private filed in the bootstrapper.

2.       Register the shell as Singleton in the container (this is good only if need to access the shell instance from several places, if not the first option is better).  You might check How to: Register and Use Services

 

Please let me know if it helps.

 

Matias Bonaventura

http://blogs.southworks.net/matiasb

Jun 12, 2009 at 6:36 PM

Thanks for your help, I really appreciate it! I've decided to keep a private reference to the shell in the bootstrapper. It works like I had been hoping it would.

I will have to read the documentation on Container.Resolve<>() to understand why it was creating a new instance.