Still looking for a sponsor Max Paulousky is looking for a Silverlight/.Net job in the Commonwealth

Share to Facebook Tweet this! Share to MySpace Share to Google Share to Live   Share via AddThis

Modularity in Silverlight Applications - An Issue With ModuleInitializeException – Part 2

Intro

In the previous article I described the problem and outlined how I would solve it. My solution was to understand what assembly(-ies) were not loaded into application domain and load them.

Solution for Silverlight applications

Let’s imagine, there is a module, that contains 3rd-party controls and the host module (Shell) does not have references to these assemblies.

The key point in the MVVM Silverlight application, that is responsible for Modules loading, is the GetModuleCatalog() method in the Bootstrapper implementation.

There are several ways to load modules:

  1. Using XAML file as a storage that contains metadata for modules and modules groups for the application.
  2. Define modules in the code to programmatically register them.

Using XAML as catalog

<Modularity:ModuleCatalog xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  xmlns:Modularity="clr-namespace:Microsoft.Practices.Composite.Modularity;assembly=Microsoft.Practices.Composite">
 
  <Modularity:ModuleInfoGroup Ref="SLErrorRendering.Module.xap" InitializationMode="WhenAvailable">
    <Modularity:ModuleInfo ModuleName="DemoModule" ModuleType="SLErrorRendering.Module.DemoModule, SLErrorRendering.Module, Version=1.0.0.0" />
  </Modularity:ModuleInfoGroup>
</Modularity:ModuleCatalog>
protected override IModuleCatalog GetModuleCatalog()
{
  return ModuleCatalog.CreateFromXaml(new Uri("/SLErrorRendering;component/ModulesCatalog.xaml", 
    UriKind.Relative));
}

The first approach uses XapModuleTypeLoader.cs (check sources of the Composite Application Guidance, <Installation Folder>\CAL\Silverlight\Composite\Modularity\). This kind of loader extract all referenced assemblies from the AppManifest.xaml file (it is the obligatory one in any XAP file; XapModuleTypeLoader.cs line 97) , extract referenced assemblies as a stream (XapModuleTypeLoader.cs, line 132) and loads them to the Application Domain (XapModuleTypeLoader.cs, line 136).

That means, any module, loaded via XAML catalog, loads all referenced assemblies to the Application Domain. So, it should not cause any problems.

Registering modules at runtime

protected override IModuleCatalog GetModuleCatalog()
{
  ModuleCatalog catalog = new ModuleCatalog();
  catalog.AddModule(typeof(DemoModule));
  return catalog;
}

This approach has some problems. If I add Composite Application Guidance sources to the project and start debugging from the point of adding module to the catalog, I will reach the ModuleNeedsRetrieval(ModuleInfo moduleInfo) method (<Installation Folder>\CAL\Silverlight\Composite\Modularity\ModuleManager.cs, line 96).

protected virtual bool ModuleNeedsRetrieval(ModuleInfo moduleInfo)
{
  if (moduleInfo.State == ModuleState.NotStarted)
  {
    // If we can instantiate the type, that means the module's assembly is already loaded into 
    // the AppDomain and we don't need to retrieve it. 
    bool isAvailable = Type.GetType(moduleInfo.ModuleType) != null;
    if (isAvailable)
    {
      moduleInfo.State = ModuleState.ReadyForInitialization;
    }
 
    return !isAvailable;
  }
 
  return false;
}

This method checks whether module needs to be retrieved before the initialization. If I register the module in the catalog at runtime, this method will return ‘false’ – the module do not need to be retrieved and all referenced assemblies will not be loaded into the Application Domain. In that case, the application will generate exception as described in the previous part of the article.

The easiest way to solve the problem is to get the list of referenced assemblies and load them into the domain. But one issue breaks all intentions.

Silverlight framework DOES NOT PROVIDE access to the GetReferencedAssemblies() method of the Assembly instance because of security reason. So, I cannot get list of the referenced assemblies and cannot load required one.

I do not see a way out for MVVM Silverlight applications with registering modules at runtime until the Silverlight team implements the mentioned method.

On the other hand, if the team could, they would implement it and would not create the <Deployment.Parts> section in the AppManifest.xaml file.

Anyway, I have created a request on Silverlight Feature Suggestions Forum to implement the GetReferencedAssemblies() method. You can vote for it here

WPF applications

In contrast to Silverlight, WPF applications load all referenced assemblies automatically. I have tested three variants of the getting module catalog implementation (ConfigurationModuleCatalog, DirectoryModuleCatalog and registering modules at runtime). All of them are working well and they load all referenced assemblies automatically.

Conclusion

According to my investigation, the ‘XamlParseException: AG_E_PARSER_BAD_TYPE‘ issue can appear in Silverlight MVVM applications that use registering modules at runtime. If modules contain assemblies that are not loaded to the application domain, the application will raise the exception, because XAML parser cannot render unknown controls. At the moment, I do not know any solution for this issue. You can vote for a feature that can help to solve that problem here.

But developers can avoid this issue, if they use XAML catalog. In this case, XapModuleTypeLoader class will read all referenced assemblies from the <Deployment.Parts> section in the AppManifest.xaml and load them into the application domain.

WPF applications do not have such a problem. They load all referenced assemblies of a module right after the module has been loaded.

Hope, this helps!

This work is licensed under a Creative Commons Attribution By license.

Leave a Comment [ RSS ]

  • re: Modularity in Silverlight Applications - An Issue With ModuleInitializeException – Part 2

    Requesting Gravatar... ross says:

    Thanks, this put me on the right track to solving a problem.

    My problem was somewhat the inverse of yours. I had say 3 modules, shell, A and B.

    Shell referenced A and B referenced A.

    If you don't set the copy-local = false on your reference to A in your B project, it gives an obscure runtime exception which I believe is something to do with A already being loaded.

  • re: Modularity in Silverlight Applications - An Issue With ModuleInitializeException – Part 2

    you can use my XapsMinifier to set copyLocal=false in such situations
    www.maxpaulousky.com/.../...e-xap-files-again.aspx

Comments have been closed on this topic.