none
WPF程序如何实现不跨AppDomain又能动态卸载插件Assembly? RRS feed

  • 问题

  • 在搭一个框架, 业务模块的ui做为插件的形式, 具体上是一个个的assembly(dll), 在运行时动态的加载并显示到主窗口上

    由于需要实现业务模块的unload, 那么只能以appdomain的形式来加载这些业务模块的程序集.

    wpf中有add-in框架可以实现把wpf ui对象在两个appdomian之间进行传送 (INativeHandleContract)

    可是这种方法最大的毛病是, 业务模块实现的ui组件通过这种方式传送后, 变成了一个win32窗口附加到主窗口上, 带来的后果是, 本来ui组件的background是透明的, 传送后由于变成了win32窗口, 就不再是透明的了.

     

    不知可有办法实现我的需求呢

    要能实现unload

    2011年1月4日 12:54

答案

  • Prism框架不正是用来解决这类问题的吗? 主界面是一个Shell,Shell里定义了多个Region,可以理解为asp.net的PlaceHolder. 程序可以分解为多个Module,ModuleManager可以按需加载Module,并把Module里的View inject进Shell的Region里。 Module当然是独立的assembly了。 参考:http://prism.codeplex.com 至于动态卸载Module,这个可以参考Prism框架的View-Based Navigation实现。也就是根据需要向Region里inject进不同Module里的View,至于原来的Module是保留还是销毁也可以人为控制。这方面我自己还不太熟悉,但大概就是这种意思。
    2011年1月4日 23:25
  • 你好 永乐,

    其实一旦一个程序集被加载到一个 AppDomain之后,在整个AppDomain的生命周期里面,他是不可能被Unload的。除非你把相应的AppDomain卸载下来。所以,一方面,你的这个要求是不可能实现的。

    参考下下面的文章吧:http://www.codeproject.com/KB/cs/Assemblies___Appdomains.aspx 通过一个AppDomain来实现Load/Unload程序集。

    另一方面,非常推荐你看下Prsim,或者一些其他的MVVM架构,他们都很好的实现了动态加载 Module:

    关于你最初的问题,你完全可以在你的Add-in框架里面设计一个专门承载WPF 内容的容器,比如说一个WPF Host Window,然后你就可以把各种内容动态的加载上去,而不会由于变成Win32的模式,使得Airspace问题发生。

     

    Jarrey

     


    Best day, Best life
    2011年1月6日 13:37
  • prism 的动态加载只是在运行时加载相应的ViewModel和资源,当然我们可以把VM设计到一个个独立的assembly里面,这样自己实现runtime加载assembly也是很简单的。

    是指逻辑上的动态加载还是物理上利用appdomain来实现的?" 逻辑上的,物理上还是只有一个Appdomain在工作。

    Unload只是逻辑上的VM示例被注销而已,并是不所谓的程序集被Unload.

     

    --> 我在考虑有没有可能利用wpf本身ui跟逻辑分离的特性, 把模块的ui当成一个文件来读取,这样读完呈现后, 程序集不会被占用, 可以随时更新, 而具体的逻辑用appdomain来加载程序集, 用完可以unload, 程序集可以更新.

    我之前提到的UI分离,使用XAML作为独立文件来访问就可以,或者更巧妙点,我们可以把XAML信息当作字符串存放在任意地方,比如网络,数据库,这样实现管理就更方便,而且在XAMLReader看来,只要是一串Xaml就可以反序列化,就可以生成对象;甚至更巧妙,我们还可以使用CodeDom来动态编译C# VB.Net代码,这样就会更灵活的来设计我们的应用。


    Best day, Best life
    2011年1月10日 17:51

全部回复

  • 永乐你好。

    我想你已经清楚认识到了这个问题中“鱼与熊掌不可兼得”的事实。

    有一个问题:为什么一定要unload那些assembly?如果某个组件不需要了,把它从UI上去掉,让它被GC,仍然会带来很大的内存、性能压力吗?你有很多的插件要加载吗?还是那些assembly里面会有一些静态类型、数据,一旦被初始化之后就会一直占用资源?

    希望能够更加详细地了解需求背景。


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    If you have any feedback, please tell us.

    The All-In-One Code Framework Project
    My Blog (in Simplified Chinese)
    2011年1月4日 14:20
    版主
  • Prism框架不正是用来解决这类问题的吗? 主界面是一个Shell,Shell里定义了多个Region,可以理解为asp.net的PlaceHolder. 程序可以分解为多个Module,ModuleManager可以按需加载Module,并把Module里的View inject进Shell的Region里。 Module当然是独立的assembly了。 参考:http://prism.codeplex.com 至于动态卸载Module,这个可以参考Prism框架的View-Based Navigation实现。也就是根据需要向Region里inject进不同Module里的View,至于原来的Module是保留还是销毁也可以人为控制。这方面我自己还不太熟悉,但大概就是这种意思。
    2011年1月4日 23:25
  • 嗯,其实说到底, unload主要是为了在运行时能动态更新组件
    2011年1月5日 1:56
  • 你好 永乐,

    其实一旦一个程序集被加载到一个 AppDomain之后,在整个AppDomain的生命周期里面,他是不可能被Unload的。除非你把相应的AppDomain卸载下来。所以,一方面,你的这个要求是不可能实现的。

    参考下下面的文章吧:http://www.codeproject.com/KB/cs/Assemblies___Appdomains.aspx 通过一个AppDomain来实现Load/Unload程序集。

    另一方面,非常推荐你看下Prsim,或者一些其他的MVVM架构,他们都很好的实现了动态加载 Module:

    关于你最初的问题,你完全可以在你的Add-in框架里面设计一个专门承载WPF 内容的容器,比如说一个WPF Host Window,然后你就可以把各种内容动态的加载上去,而不会由于变成Win32的模式,使得Airspace问题发生。

     

    Jarrey

     


    Best day, Best life
    2011年1月6日 13:37
  • 1,我原来的标题不是这样.我当然知道unload assembly得通过unload appdomain来实现

    2,wpf本身框架实现的跨appdomain传送ui是用一个win32子窗口贴到主窗体里来实现的, 结果是跟不跨appdomain差别实在太多. 

    至于你说的wpf host window, 这跟wpf本身框架实现的我看不出来有啥区别

     

    prism我不了解, 上面有几位都提到这个东西, 我想请教一下, 他们的动态加载module是怎么实现的呢?是指逻辑上的动态加载还是物理上利用appdomain来实现的?

    我想也不是appdomain吧?? 我想也不能真正的unload吧?

     

     

    ps: wpf本身的frameworkelement, 不是实实在在的win32窗口, 不像传统应用程序里一个textbox, 一个button都对应一个win32窗口,所以这些frameworkelement的呈现非常灵活, 最简单来说, 他们可以跟背景无缝的容合, 实现透明之类.  而如果跨appdomain传送一个frameworkelement, wpf会把这个frameworkelement放入一个win32窗口, 然后真正传送的是其win32窗口句柄,接收端获得窗口句柄后把窗口做为子窗口嵌入到主窗口中.  这里这个win32窗口我想本身应该就是WPF Host Window了.

    2011年1月7日 2:15
  • 好像一谈到动态加载, 大家就会说到prism, 我不知道你们对prism是否真的了解

    我不知道prism里的动态加载是什么概念

    但我这里所谓的动态加载, 很简单, 就是物理上的load和unload程序集

    希望有对prism比较了解的哥们来解惑

     

    现在看来用appdomain来实现unload plugin应该是不可能的任务了.

     

    我在考虑有没有可能利用wpf本身ui跟逻辑分离的特性, 把模块的ui当成一个文件来读取,这样读完呈现后, 程序集不会被占用, 可以随时更新, 而具体的逻辑用appdomain来加载程序集, 用完可以unload, 程序集可以更新.

     

     

    2011年1月7日 2:31
  • 完全可以, 你把UI设计成独立的XAML, 然后使用XAMLReader来动态读取就行了。

     


    Best day, Best life
    2011年1月7日 17:49
  • prism 的动态加载只是在运行时加载相应的ViewModel和资源,当然我们可以把VM设计到一个个独立的assembly里面,这样自己实现runtime加载assembly也是很简单的。

    是指逻辑上的动态加载还是物理上利用appdomain来实现的?" 逻辑上的,物理上还是只有一个Appdomain在工作。

    Unload只是逻辑上的VM示例被注销而已,并是不所谓的程序集被Unload.

     

    --> 我在考虑有没有可能利用wpf本身ui跟逻辑分离的特性, 把模块的ui当成一个文件来读取,这样读完呈现后, 程序集不会被占用, 可以随时更新, 而具体的逻辑用appdomain来加载程序集, 用完可以unload, 程序集可以更新.

    我之前提到的UI分离,使用XAML作为独立文件来访问就可以,或者更巧妙点,我们可以把XAML信息当作字符串存放在任意地方,比如网络,数据库,这样实现管理就更方便,而且在XAMLReader看来,只要是一串Xaml就可以反序列化,就可以生成对象;甚至更巧妙,我们还可以使用CodeDom来动态编译C# VB.Net代码,这样就会更灵活的来设计我们的应用。


    Best day, Best life
    2011年1月10日 17:51