Prism OnDemand 模块加载是否可以在 OOB 场景中工作?
OnDemand Prism 模块的加载是否应该在 OOB 场景中工作?如果是这样,我似乎无法让它发挥作用。目前一切都在浏览器中运行,没有任何问题。具体来说我: 在代码中注册我的模块:
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.Host.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 );
}
稍后发出对要加载的模块的请求:
mModuleManager.LoadModule( ModuleNames.mod2 );
并等待对该加载模块初始化期间发布的事件的响应。
该模块似乎从未被加载,并且当应用程序在调试器下运行时,将会出现一个消息框,指出 Web 服务器返回了“未找到”错误。我可以获取该模块的请求 URL,并将其输入 Firefox 并毫无问题地下载该模块。
我还没有找到任何关于这实际上可行的参考,但似乎应该如此。我在这个主题上找到的最多的是 Jeremy 的 博客条目Likeness,其中介绍了在 MEF 中加载模块,但在这里应用他的知识并没有帮助。
服务器是本地主机(我听说这可能会导致问题)。服务器有一个 clientaccesspolicy.xml 文件 - 尽管我不认为需要它。 我正在使用客户端堆栈并在应用程序构建期间注册它:
WebRequest.RegisterPrefix( Current.Host.Source.GetComponents( UriComponents.SchemeAndServer, UriFormat.UriEscaped ), WebRequestCreator.ClientHttp );
后续问题:
可以将所有 xap 以某种方式安装到客户端桌面 - 还是仅将主应用程序 xap 安装到客户端桌面?以某种方式在 appmanifest.xml 中指定它们?
如果只安装了 application.xap 并且无论如何都必须下载其余的 xap,那么这样做是否值得?
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.Host.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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
有一次我做过类似的场景。诀窍是将模块存储在独立存储中,并使用在离线工作时从独立存储中读取的模块加载器。
这是因为否则,您将无法下载与 Shell 不同的 .xap 文件中的模块。
谢谢,
达米安
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
如果您愿意调整 Prism 源代码并自己构建它,则可以将自定义模块加载器挂接到 Prism 中。我实际上能够很容易地让它工作 - 在我们的应用程序中,我首先在磁盘上查找模块,如果没有找到,我会通过第三方商业 HTTP 堆栈从服务器加载它,该堆栈支持客户证书。
为此,请下载 Prism 源代码,并找到 Microsoft.Practices.Composite.Modularity.XapModuleTypeLoader 类。该类使用另一个 Prism 类 Microsoft.Practices.Composite.Modularity.FileDownloader 来下载 .xap 内容;但它直接实例化它,让你没有机会注入你自己的或其他什么。
因此 - 在 XapModuleTypeLoader 中,我添加了一个静态属性来设置下载器的类型:
然后我修改了 CreateDownloader() 方法以优先使用上面指定的类型而不是默认类型:
当我的应用程序启动时,我将该属性设置为我自己的下载器类型:
瞧 - 现在 Prism 调用您的代码来加载其模块。
如果您有兴趣,我可以向您发送我的 LocalFileDownloader 类以及它返回到的用于从网络加载 .xap 的类...但我怀疑,如果您查看 Prism 的 FileDownloader 类,您会发现它很简单足够的。
关于您的其他问题,如果安装应用程序的 URL 与您正在交谈的 URL 相同,或者您的信任度较高,则可能不需要 clientaccesspolicy.xml 文件。
.xaps 绝对可以预先安装在客户端上,但这需要一些工作。我们所做的是编写一个启动器应用程序,它是一个独立的 .NET 2.0 桌面应用程序。它会下载主 .xap 以及某些模块*(检查更新并仅根据需要下载),然后在必要时卸载/重新安装应用程序,然后启动应用程序。最后两个是通过 sllauncher.exe 完成的,它作为 Silverlight 的一部分安装。这是一个很好的介绍: http://timheuer.com/blog/archive/2010/03/25/using-sllauncher-for-silent-install-silverlight-application.aspx。
假设您在提升的信任度下运行,还应该可以从 SL 客户端内预取模块 .xaps,但在用户操作实际请求它们之前。您只需将它们放在“我的文档”下的某个文件夹中,然后使用上面描述的自定义模块加载方法从那里提取它们。
*在我们的例子中,我们的主 .xap 是应用程序的 2/3。我们的其余 .xap 都很小,因此我们会即时下载它们,但我们为第三方组件创建作为容器的一些 .xap 除外。我们不希望经常更新这些内容,因此我们预先安装了它们。
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:
Then I modified the CreateDownloader() method to use the type specified above in preference to the default one:
When my app starts up, I set the property to my own downloader type:
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.