Modules Not Being Initialized if Already Loaded via Unity

Topics: Prism v2 - WPF 4
Aug 27, 2010 at 5:52 PM
Edited Aug 27, 2010 at 5:54 PM

Hello,

I'm having a strange problem where one of my modules isn't being initialized if I use Unity to register one of its types. Here's what I think is happening:

I'm using configfile-based Unity configuration. The Module1 assembly is loaded into the AppDomain when Container.LoadConfiguration is called (3rd line of method, below).

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

            Container.RegisterType<IUnityContainer>();

            Container.LoadConfiguration();
        }
When the UnityBootstrapper.InitializeModules executes, the module's initialization is passed over because it is seen as already loaded in the AppDomain. That's my theory, anyway.
The config file is shown below. Any ideas on what I'm doing wrong, or on a possible workaround?
<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
    <section name="modules" type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection, Microsoft.Practices.Composite"/>
  </configSections>

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="modules"/>
    </assemblyBinding>
  </runtime>

  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <container>
      <register type="CommonLibrary.ICalculator, CommonLibrary" name="classic" mapTo="ClassLibrary1.ClassicCalculator, ClassLibrary1" />
      <register type="CommonLibrary.ICalculator, CommonLibrary" name="new" mapTo="ClassLibrary1.PostmodernCalculator, ClassLibrary1" />
      <register type="CommonLibrary.IPart, CommonLibrary" name="MainPart" mapTo="Module1.UserControl1, Module1"></register>

    </container>
  </unity>

  <modules>
    <module assemblyFile="Module1.dll" moduleType="Module1.Module1" moduleName="Module1" startupLoaded="true"/>
    <module assemblyFile="Module2.dll" moduleType="Module2.Module2" moduleName="Module2" startupLoaded="true"/>
  </modules>

</configuration>
BTW, Module2 is being initialized. I think this is because it isn't being loaded into memory by Unity.
Thanks in advance!
Sep 3, 2010 at 8:05 PM
Edited Sep 3, 2010 at 8:07 PM

Hi,

I do not know your exact scenario. Anyway, let me share some ideas that could help you with this scenario:

  • Update the moduletype in your configuration file to use a full assembly name qualified, as it is shown in bold below: 

    <module assemblyFile="ModularityWithUnity.Desktop.ModuleF.dll"

moduleType="ModularityWithUnity.Desktop.ModuleF, ModularityWithUnity.Desktop.ModuleF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" 

moduleName="ModuleF" startupLoaded="false">

  • Try to define the Module1 in your code, it is only for checking if it loaded with no issues.
  • How are you verifying that modules are loaded?
  • When you use unity to resolve, could you resolve types from module1 or module2 assemblies?

If you continue experiencing this problem, you could share any additional information to clarify this situation.

Please let me know if this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

Sep 7, 2010 at 4:13 PM
Edited Sep 7, 2010 at 4:14 PM

Hi Fernando,

Thank you for replying! Unfortunately, the suggestion to use the full assembly name made no difference. I reverted back.

In response to your bullets:

* I’m not sure what you are asking.

* I’m setting a breakpoint in the Initialize method of the IModule implementations. The breakpoints never get hit.

* Yes. However, if I register (via config file) a dependency in Module1, Module1’s Initialize won’t get called. Same with Module2. As long as I’m not registering any dependencies in the config file the modules get initialized. The following will illustrate:

 

NOTE: Module1 looks like this as well; bare-bones.

   public class Module2 : IModule

   {

       private readonly IUnityContainer _container;

        public Module2(IUnityContainer container)

       {

           _container = container;

       }

        /// <summary>

       /// Notifies the module that it has be initialized.

       /// </summary>

       public void Initialize()

       {

           _container.RegisterType<IWeatherForcaster, WeatherForcaster>();

       }

   }

    public class Bootstrapper : UnityBootstrapper

   {

       protected override DependencyObject CreateShell()

       {

           MainWindow shell = (MainWindow)Container.Resolve(typeof(MainWindow));

           shell.Show();

           return shell;

       }

        protected override IModuleCatalog GetModuleCatalog()

       {

           return new DirectoryModuleCatalog() { ModulePath = @".\modules" };

       }

        protected override void ConfigureContainer()

       {

           base.ConfigureContainer();

            Container.RegisterType<IUnityContainer>();

           Container.LoadConfiguration();

       }

   }

 

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

 <configSections>

   <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>

   <section name="modules" type="Microsoft.Practices.Composite.Modularity.ModulesConfigurationSection, Microsoft.Practices.Composite"/>

</configSections>

    <runtime>

   <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

     <probing privatePath="modules"/>

   </assemblyBinding>

</runtime>

 <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

   <container>

     <register type="CommonLibrary.ICalculator, CommonLibrary" name="classic" mapTo="ClassLibrary1.ClassicCalculator, ClassLibrary1" />

     <register type="CommonLibrary.ICalculator, CommonLibrary" name="new" mapTo="ClassLibrary1.PostmodernCalculator, ClassLibrary1" />

    

     <!--<register type="CommonLibrary.IPart, CommonLibrary" name="MainPart" mapTo="Module1.UserControl1, Module1"></register>-->

     <register type="CommonLibrary.IPart, CommonLibrary" name="MainPart" mapTo="Module2.UserControl1, Module2"></register>

   </container>

</unity>

 <modules>

   <module assemblyFile="Module1.dll" moduleType="Module1.Module1" moduleName="Module1" startupLoaded="true"/>

   <module assemblyFile="Module2.dll" moduleType="Module2.Module2" moduleName="Module2" startupLoaded="true"/>

</modules>

 </configuration>

 

As shown, Module1’s Initialize method is getting called. However, Module2’s Initialize method is not. However, if you change the config file to look like the following then Module2’s Initialize method will get called and Module1’s will not.

      <register type="CommonLibrary.IPart, CommonLibrary" name="MainPart" mapTo="Module1.UserControl1, Module1"></register>

     <!--<register type="CommonLibrary.IPart, CommonLibrary" name="MainPart" mapTo="Module2.UserControl1, Module2"></register>-->

 

I’m really not doing anything fancy. I’m surprised this is happening. Any other ideas?

 

Thanks!

Sep 23, 2010 at 8:16 PM
Edited Sep 23, 2010 at 8:18 PM

Hi,

I tried it myself, and found no issues. So, I would like to share with you some ideas that might help to solve your scenario:

  • The unity configuration section looks like the following:

  <unity xmlns="…">
    <containers>
      <container>
        <types>
          <type type="CommonLibrary.IPart, CommonLibrary" mapTo="ModuleA.PartA, ModuleA" name="Test"></type>
        </types>
      </container>
    </containers>
  </unity>

  • It is necessary to configure my container programmatically using the following code:
IUnityContainer container = new UnityContainer();
UnityConfigurationSection section
  = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
section.Containers.Default.Configure(youContainer);

For more information about this you could take a look at the following documentation section: Configuring Containers at Design Time

I hope this helps,

Fernando Antivero
http://blogs.southworks.net/fantivero