Relative file paths for modules defined in Xaml are not resolved correctly. In some discussions it is stated that the relative paths are resolved correctly if the modules are located directly in the current working directory, but this does not seem to be the case either.
I believe the only reason it "works" when the modules are located directly in the current working directory is that the file path is never resolved by Prism - instead it is resolved by a call to Type.GetType(moduleInfo.ModuleType), hence ignoring the Ref-attribute. So if your module is loaded with a relative path in the Xaml, you can change it to a non-existing filename and it will still load, such as Ref="file:///ThisFileDoesn'tExist".
To fix it the right way, I guess changes should be made several places in code. However, if the relative paths are converted into absolute paths, this issue will not appear. To do this in the Prism-source, locate line 149 in ModuleCatalog.cs (in method CreateFromXaml(Stream xamlStream) ). It currently is:
return XamlReader.Load(xamlStream) as ModuleCatalog;
Change it into this:
ModuleCatalog xamlModuleCatalog = XamlReader.Load(xamlStream) as ModuleCatalog;
foreach (ModuleInfo moduleInfo in xamlModuleCatalog.Modules)
{
Uri uriRef;
if (Uri.TryCreate(moduleInfo.Ref, UriKind.RelativeOrAbsolute, out uriRef))
{
if (uriRef.IsFile && !Path.IsPathRooted(uriRef.LocalPath.TrimStart('/')))
{
// Since we work with Uri's, it is most appropriate to let the Uri class handle the concatenation.
Uri newUriRef = new Uri(new Uri(Directory.GetCurrentDirectory() + '\\'), uriRef.LocalPath.TrimStart('/'));
moduleInfo.Ref = "file:///" + newUriRef.OriginalString;
}
}
}
return xamlModuleCatalog;
If you do not want to change the Prism-source, simply create a FileStream to the Xaml document and then you can use the same code as above. Something like this:
FileStream xamlStream = System.IO.File.OpenRead("ModuleCatalog.xaml")
// Rest of the code here
A sidenote: If you accidentally change the name of a an IModule class that is referred to in the Xaml module catalog (so the class name in Xaml is different from the real class name), you will get this error:
“Failed to load type for module SomeModule.
If this error occurred when using MEF in a Silverlight application, please ensure that the CopyLocal property of the reference to the MefExtensions assembly is set to true in the main application/shell and false in all other assemblies.
Error was: Unable to find the specified file..”
That is quite difficult to debug, since the path to the file is specified correctly. After applying the above fix, you will get a more helpful error message:
“Unable to retrieve the module type SomeModuleClass, SomeModuleAssemblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null from the loaded assemblies. You may need to specify a more fully-qualified type name.”
Another sidenote: This fix also lets you place the modules in subfolders like this: Ref="file:///PrismModules/ModuleA/ModularityWithUnity.Desktop.ModuleA.dll"
Since there are login-instructions to the TFS in the “source code” area on this site, I tried to login to TFS and fix the issue. However I got “Access Denied” when trying to login.
NOTE: I just wrote that bug fix code and have only tested it a few minutes on my own system. It seems to work, but I haven’t tested it much!