Strange Voodoo Module Caching in Prism v4+MEF Silverlight OOB

Topics: Prism v4 - Silverlight 4
Jan 21, 2011 at 11:27 PM

I am getting a really strange behavior in Silverlight OOB Modules (note: NOT offline):

If the modules are loaded during bootstrapping I do not experience the problem, but recently I moved the module load to after login so I could load modules based on user profile, and the problem started happening ... here is what is happening:

The module being loaded is not the current version; I can tell this is the case because the debugger can't hit the breakpoint becuase no symbols are loaded and because the latest changes I made are not reflected in the module.

Here is how I am loading the modules after login (in case it has bearing):

// TODO: define available modules via non-coded meta data
string basePath = (Application.Current.IsRunningOutOfBrowser ? "http://localhost:65400/ClientBin/" : "");
var availableModules = new List<ModuleInfo>()
{
{new ModuleInfo() { ModuleName = "ReceptionModule", Ref = basePath + "PatientJourney.Reception.xap", InitializationMode = InitializationMode.WhenAvailable }},
{new ModuleInfo() { ModuleName = "NurseModule",     Ref = basePath + "PatientJourney.Nurse.xap",     InitializationMode = InitializationMode.WhenAvailable }}
};

// Load modules identified in current users profile
var modules = availableModules.Where(m => userModules.Contains(m.ModuleName));
foreach (var module in modules)
{
this.ModuleCatalog.AddModule(module);
}

this.ModuleManager.Run();

It gets even stranger because a complete reload of the dev environments and asp.net dev servers does not clear the problem ... but, loading the changed modules up via the bootstrapper will load the new changes ... then loading the modules after login will now have the latest changes.


Jan 24, 2011 at 10:38 PM
Edited Jan 25, 2011 at 2:50 PM

Hi,

Since modules are loaded in the Prism initialization sequence by the Bootstrapper (which calls the ModuleManager.Run method), you shouldn’t call that method by yourself, unless you override the InitializeModules method of your Bootstrapper to remove that call.

Based on my understanding of your scenario, you could benefit from using on-demand module loading, for example like this:

 

 

 

Additionally, you might find some of the following threads useful, as they deal with the subject of login in Prism.

You can read more about modularity in the aforementioned chapter.

I hope you find this information useful.

Thanks,

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

 

protected override void ConfigureModuleCatalog()
{
      Type moduleCType = typeof(ReceptionModule);

      this.ModuleCatalog.AddModule(new ModuleInfo()
      {
            ModuleName = moduleCType.Name,
            ModuleType = moduleCType.AssemblyQualifiedName,
            InitializationMode = InitializationMode.OnDemand
      });
…
} 

 

You can read more about remote on-demand and remote module loading in Chapter 4: Modular Application Development from the Prism documentation, as well as in the Modularity QuickStart, where you might find another example of how this is achieved.

Jan 25, 2011 at 7:28 PM

I get the same caching / debug (or lack thereof) after changing to load OnDemand, so it appears that it is an issue with Prism+MEF+Silverlight+OOB; here is what I tried:

I set all of the modules to OnDemand and have them configured in the catalog as follows:

public class PatientJourneyBootstrapper : MefBootstrapper
{
    ...
    protected override IModuleCatalog CreateModuleCatalog()
{
string basePath = (Application.Current.IsRunningOutOfBrowser ? "http://localhost:9000/ClientBin/" : "");
var availableModules = new List<ModuleInfo>()
{
{new ModuleInfo() { ModuleName = "ReceptionModule", Ref = basePath + "PatientJourney.Reception.xap", InitializationMode = InitializationMode.OnDemand }},
{new ModuleInfo() { ModuleName = "NurseModule",     Ref = basePath + "PatientJourney.Nurse.xap",     InitializationMode = InitializationMode.OnDemand }}
};
        return new ModuleCatalog(availableModules);
}

Then I load the relevant modules after login as follows:

private void LoadUserModules(List<string> userModules)
{
foreach (var moduleName in userModules)
{
this.ModuleManager.LoadModule(moduleName);
}
}

 

Developer
Jan 26, 2011 at 3:25 PM
Edited Jan 26, 2011 at 5:39 PM

Hi,

You could try specifying the type of your module when you instantiate the ModuleInfo class (for example using this overload of the constructor). Another possibility would be to use other ways of creating a module catalog, for example creating configuration module catalog from a xaml catalog. You can read more about that in this chapter from the Prism MSDN documentation.

Additionally, you could try the approach mentioned in this thread, which might be helpful in case your modules are being cached:

browser caching module xap

Let us know if you keep experiencing the same problem after trying out the aforementioned possibilities.

I hope you find this helpful.

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


Jan 26, 2011 at 6:12 PM

Loading from Xaml catalog would not have any bearing as it would be loading the same info in the bootstrapper regardless, and I don't quite follow you on the ModuleInfo overload, what type would the xap file be?

But I looked into the browser caching module xap, and that resolved the problem by sending a varying query parameter (kind of ugly hack, but it worked) Thanks!:

public class PatientJourneyBootstrapper : MefBootstrapper
{
    ...
    protected override IModuleCatalog CreateModuleCatalog()
{
string basePath = (Application.Current.IsRunningOutOfBrowser ? "http://localhost:9000/ClientBin/" : "");
string noCache = (Application.Current.IsRunningOutOfBrowser && System.Diagnostics.Debugger.IsAttached ? "?Unused=" + new Guid() : "");
var availableModules = new List<ModuleInfo>()
{
    {new ModuleInfo() { ModuleName = "ReceptionModule", Ref = basePath + "PatientJourney.Reception.xap" + noCache, InitializationMode = InitializationMode.OnDemand }},
    {new ModuleInfo() { ModuleName = "NurseModule",     Ref = basePath + "PatientJourney.Nurse.xap" + noCache,     InitializationMode = InitializationMode.OnDemand }}
};
 
        return new ModuleCatalog(availableModules);
    }
    ...
}
 
Developer
Jan 26, 2011 at 6:26 PM

Hi,

I'm glad that you've solved your caching issue with the solution proposed in the thread I've sent to you.

As for the type parameter of your ModuleInfo, you could specify the fully qualified name of your assembly. For example:

ModuleType="NurseModule.NurseModule, NurseModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

I've created a work item in the Issue Tracker for the caching issue you've experienced, so that it is considered for future releases.

Thank you for your feedback.

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