Should the loading of OnDemand Prism modules work in an OOB scenerio? If so, I cannot seem to make it work. Everything is currently working in browser without any problems. Specifically I: register my modules in code:
protected override IModuleCatalog GetModuleCatalog() {
var catalog = new ModuleCatalog();
Uri source;
if( Application.Current.IsRunningOutOfBrowser ) {
source = IsolatedStorageSettings.ApplicationSettings[SOURCEURI] as Uri;
}
else {
var src = Application.Current.H开发者_如何转开发ost.Source.ToString();
src = src.Substring( 0, src.LastIndexOf( '/' ) + 1 );
source = new Uri( src );
IsolatedStorageSettings.ApplicationSettings[SOURCEURI] = source;
IsolatedStorageSettings.ApplicationSettings.Save();
}
if( source != null ) {
var mod2 = new ModuleInfo { InitializationMode = InitializationMode.OnDemand,
ModuleName = ModuleNames.mod2,
ModuleType = "mod2.Module, mod2.Directory, '1.0.0.0', Culture=neutral, PublicKeyToken=null" ),
Ref = ( new Uri( source, "mod2.xap" )).AbsoluteUri };
catalog.AddModule( mod2 );
}
// per Jeremy Likeness - did not help.
Application.Current.RootVisual = new Grid();
return ( catalog );
}
later request for the module to be loaded is made:
mModuleManager.LoadModule( ModuleNames.mod2 );
and wait for a response to an event published during the initialization of that loaded module.
The module appears to never be loaded, and when the application is running under the debugger there will be a message box that states that the web server returned a 'not found' error. I can take the requesting url for the module and enter it into Firefox and download the module with no problem.
I have not been able to find any reference to this actually being workable, but it seems as though it should. The most I have found on the subject is a blog entry by Jeremy Likeness, which covers loading modules in MEF, but applying his knowledge here did not help.
The server is localhost (I have heard it mentioned that this might cause problems). The server has a clientaccesspolicy.xml file - although I don't expect that is needed. I am using the client stack and register it during app construction:
WebRequest.RegisterPrefix( Current.Host.Source.GetComponents( UriComponents.SchemeAndServer, UriFormat.UriEscaped ), WebRequestCreator.ClientHttp );
Followup questions:
Can all of the xaps be installed to the client desktop in some manner - or only the main application xap? specify them in appmanifest.xml somehow??
Is it worth it make this work if only the application.xap is installed and the rest of the xaps must be downloaded anyway?
Once I worked on a similar scenario. The trick is having the modules stored in isolated storage and use a module loader that reads from isolated storage when working offline.
This is because otherwise, you can't get download the modules that are in a different .xap file than the Shell.
Thanks, Damian
It is possible to hook custom module loaders into Prism if you're willing to tweak the Prism source and build it yourself. I was actually able to get this to work pretty easily - in our app, I look on disk first for the module, and if it's not found, I fall back to loading it from the server via a third-party commercial HTTP stack that supports client certificates.
To do this, download the Prism source code, and locate the Microsoft.Practices.Composite.Modularity.XapModuleTypeLoader class. This class uses another Prism class, Microsoft.Practices.Composite.Modularity.FileDownloader, to download the .xap content; but it instantiates it directly, giving you no chance to inject your own or whatever.
So - in XapModuleTypeLoader, I added a static property to set the type of the downloader:
public static Type DownloaderType { get; set; }
Then I modified the CreateDownloader() method to use the type specified above in preference to the default one:
protected virtual IFileDownloader CreateDownloader() {
if (_downloader == null) {
if (DownloaderType == null) {
_downloader = new FileDownloader();
} else {
_downloader = (IFileDownloader)Activator.CreateInstance(DownloaderType);
}
}
return _downloader;
}
When my app starts up, I set the property to my own downloader type:
XapModuleTypeLoader.DownloaderType = typeof(LocalFileDownloader);
Voila - now Prism calls your code to load its modules.
I can send you my LocalFileDownloader class as well as the class it falls back to to load the .xap from the web if you're interested... I suspect though that if you look at Prism's FileDownloader class you'll see that it's simple enough.
With regard to your other questions, the clientaccesspolicy.xml file is probably not needed if the URL the app is installed under is the same one you're talking to, or if you're in elevated trust.
The .xaps can definitely be pre-installed on the client, but it's a bit of work. What we did was write a launcher app that is a standalone .NET 2.0 desktop app. It downloads the main .xap plus certain modules* (checking for updates and downloading only as needed), then uninstalls/reinstalls the app if necessary, then launches the app. The last two are done via sllauncher.exe, which is installed as part of Silverlight. Here's a good intro to that: http://timheuer.com/blog/archive/2010/03/25/using-sllauncher-for-silent-install-silverlight-application.aspx.
Assuming you're running under elevated trust, it should also be possible to pre-fetch the module .xaps from within the SL client, but before they're actually requested due to user action. You'd just need to put them in a folder under My Documents somewhere, and then use the custom module loading approach described above to pull them from there.
*In our case, our main .xap is 2/3 of the application. The rest of our .xaps are small, so we download them on-the-fly, with the exception of some .xaps we created as containers for third-party components. We don't expect to update those very often, so we pre-install them.
精彩评论