IModule.Initialized not getting called.

Topics: Prism v4 - WPF 4
Jun 28, 2011 at 1:07 AM
Edited Jun 28, 2011 at 5:36 AM

Hi, I am exploring modules using MEF. I have a CustomerModule exported using [ModuleExport], but this module's Initialize() and constructor never gets called. Certainly, it seems I am missing some wire-up code. Here are the relevant parts of code.

//CustomerModule

[ModuleExport(typeof(CustomerModule), InitializationMode = InitializationMode.WhenAvailable)]
    public class CustomerModule : IModule {
    public void Initialize() { //Never gets called.
            RegionViewRegistry.RegisterViewWithRegion("MainRegion", typeof(CustomerViewModel));
...
    }
}

//MefBootstrapper

        protected override IModuleCatalog CreateModuleCatalog() {
            return new ConfigurationModuleCatalog();
        }


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

            this.AggregateCatalog.Catalogs.Add(
                new AssemblyCatalog (typeof(CustomerModule.CustomerModule).Assembly));
}

Any suggestions why CustomerModule.Initialize() (and constructor too) is never called.

regards,

Nirvan.

Jun 28, 2011 at 3:27 PM

Hi Nirvan,

Based on the description of your scenario, there doesn’t seem to be any problem with the code you’ve shown here. However you could try re check the Run’s sequence in your Boostrapper in order to verify everything is running correctly. Remember also to check your App.xaml.cs code behind and check the OnStartUp method to verify how you are instantiating and calling the Bootstrapper’s Run method.

You could use WPF using MEF QuickStarts provided with Prism to help you compare the code.

In case you continue experiencing this behavior, it could be helpful if you could provide us with a repro sample (for example, uploading to SkyDrive) of your solution, so that we can help you find out the cause.

Thanks,

Miguel Bronzovic
http://blogs.southworks.net/mbronzovic

 

Jun 28, 2011 at 4:25 PM
Edited Jun 28, 2011 at 6:19 PM

Guido/Bronzovic,

I checked the Bootstrapper Run sequence and it seems to be normal. Here is the sequence of invocation.

  1. protected override IModuleCatalog CreateModuleCatalog() 
  2. protected override void ConfigureAggregateCatalog()
  3. protected override void ConfigureContainer()
  4. protected override DependencyObject CreateShell()
  5. protected override void InitializeShell()

I debugged and saw that the AggregateCatalog has all the entries for my modules(Views and ViewModels). So AggregateCatalog is properly populated. But the ModuleCatalog's Modules is Empty Collection. How is that the ModuleCatalog and AggregateCatalog is out of sync. The Application runs alright (except for region discovery, for which I will probably start a new discussion) , but I don't get a chance to Initialize CustomerModule.cs as it is never called. So in short all parts get exported, except the actual CustomerModule.cs (which implements IModule). 

regards,
Nirvan. 

Note: I don't have account with sky drive or any service, so I cannot post the repro. Will open one shortly.

Jun 28, 2011 at 6:03 PM
Edited Jun 28, 2011 at 6:28 PM

Guido/Bronzovic,

I have my skydrive account active now. What do you want me to upload on skydrive ? I mean, does repro mean the whole solution ? In that case you can find the same here. After the Shell loads the MainRegoin, click on Customer Button in the toolbar. The CustomerModule Constructor is not invoked at any point.

regards,

Nirvan.

Developer
Jun 28, 2011 at 7:16 PM

Hi Nirvan,

A repro sample usually means a sample application that is intended to reproduce a specific behavior that you're experiencing. In some cases, a repro sample might be the whole solution, although showing a scenario scoped only to the exact problem that you want to point out might depict your point in a clearer way.

As for the problems you're experiencing, the problem is caused by the fact that you are experiencing some CompositionExceptions, due to the fact that you're trying to get imports in an incorrect way. When registering services, it's a common good practice to export types using the interface as the contract; that is to say, if you have (for example) the EventAggregator class, you should export it with the IEventAggregator interface as the contract type. Therefore, other components can "know" of the interface, but not of the exact implementation of that interface. Prism follows that approach, and therefore, exports for services use the interface as the contract type. Therefore, when importing Prism's services, such as the region view registry, you should indicate that your import is of type IRegionViewRegistry, not RegionViewRegistry. In your sample application, we've replaced all the imports for Prism services with the corresponding interface, and after that, your module was initialized correctly.

To illustrate this:

 

[ModuleExport(typeof(CustomerModule), InitializationMode = InitializationMode.WhenAvailable)]
    public class CustomerModule : IModule {

        public CustomerModule()
        {

        }

        // This is correct
        [Import]
        IRegionViewRegistry RegionViewRegistry { get; set; }


        // This is incorrect
        //[Import]
        //RegionViewRegistry RegionViewRegistry { get; set; }

        public void Initialize()
        {

        }
    }

 

Additionally, we've examined your sample and found that you're importing your module's exports (such as the view models for your views) directly in your shell view model (for example, in the LoadCustomerModule method inside the ShellViewModel class). That might not be a good practice, as you are coupling your shell to your customer module. The approach recommended by prism is to make modules responsible for adding their views to regions defined in the shell. One possibility to cover that scenario would be to use Navigation to indicate that you should navigate to your CustomerMainViewModel in the LoadCustomerModule method.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Jun 29, 2011 at 12:53 AM

Guido,

Thanks for helping me out resolve the Module Initialization issue and guiding me about the ideal practices. I will surely have a look on Navigation part of Prism Developers guide so that decouple the Modules as much as possible. The issue in this discussion is resolved.

regards,

Nirvan.

Sep 4, 2013 at 5:43 PM
Edited Sep 4, 2013 at 5:52 PM
Hi Guido,

I found some minor bug in your code. Access modifier for RegionViewRegistry property should be public, otherwise MEF would throw an error on module initialization.
        // This is more correct :)
        [Import]
        public IRegionViewRegistry RegionViewRegistry { private get; set; }