应用程序体系结构
在我专攻代码之前,我想谈谈我尝试做的事。您可能记得,SuperGraph
让您从函数列表中进行选择。我希望能够在具体的目录中放置外接程序程序集,让 SuperGraph
检测它们,加载它们,并找到它们中包含的所有函数。
如果 SuperGraph 自己能完成此操作则不需要单独的 AppDomain。Assembly.Load() 通常运行良好,但程序集无法独立卸载(只有 AppDomain
可以卸载)。这意味着如果您正在编写服务器,而且您希望用户无需启动和停止服务器即能更新他们的外接程序,那么您将无法使用默认的
AppDomain 实现此任务。
要实现此功能,我们将在一个独立的 AppDomain 中加载所有外接程序程序集。当添加或修改文件时,我们将卸载
AppDomain,创建新的 AppDomain,然后将当前文件加载到其中。这样,一切就都完美无缺了。
为了把这个讲得更明白一点,我创建了一个典型方案,如图 1 所示。

<br> [br="">图 1:典型的
AppDomain 方案
在这个图表中,Loader 类创建一个名为
Functions 的新 AppDomain。创建 AppDomain 之后,Loader 在新的
AppDomain 中创建 RemoteLoader 的实例。
要加载程序集,请在 RemoteLoader
上调用加载函数。该函数打开新的程序集,找到程序集中的所有函数,将函数打包到 FunctionList 对象中,然后将该对象返回到 Loader。然后,就可以通过 Graph 函数使用此
FunctionList 中的 Function 对象。
创建 AppDomain
第一项任务是创建 AppDomain。要以正确的方式创建 AppDomain,我们需要向 AppDomain 传递一个
AppDomainSetup
对象。一旦您理解了这一切的工作原理,关于这些的文档就足够使用了,但是如果您正在试图理解其工作原理,那么这些文档的帮助并不大。当关于该主题的
Google 搜索将上个月的专栏作为较高的匹配之一返回时,我怀疑我可能有点麻烦了。
必须处理的基本问题是如何在运行时加载程序集。默认情况下,运行时将查看全局程序集缓存或当前应用程序目录树。而我们希望从完全不同的目录中加载我们的外接程序。
当您查看 AppDomainSetup 的文档时,您将发现可以把 ApplicationBase
属性设置为要搜索程序集的目录。然而,我们也需要参考原始的程序目录,因为那是 RemoteLoader
类存在的地方。
AppDomain 的创作者们理解这一点,因此他们已经提供了额外的位置,用于从中搜索程序集。我们将使用
ApplicationBase 引用外接程序目录,然后将 PrivateBinPath
设置为指向主应用程序目录。
下面是来自 Loader 类的代码,可实现此功能:
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = functionDirectory;
setup.PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory;
setup.ApplicationName = "Graph";
appDomain = AppDomain.CreateDomain("Functions", null, setup);
remoteLoader = (RemoteLoader)
appDomain.CreateInstanceFromAndUnwrap("SuperGraph.exe",
"SuperGraphInterface.RemoteLoader");
创建 AppDomain 之后,使用 CreateInstanceFromAndUnwrap()
函数在新的应用程序域中创建 RemoteLoader
类的实例。请注意,需要使用类所在的程序集的文件名以及类的全名。
当执行此调用时,我们返回如同 RemoteLoader
一样的实例。实际上,它是一个小型代理类,将所有调用转发到其他 AppDomain 中的 RemoteLoader
实例中。这和 .NET Remoting 使用的是同一种结构。
程序集绑定日志查看器
当您编写代码实现此功能时,您会产生错误。本文档对如何调试应用程序并未提供什么建议,但是如果您知道该向谁询问,他们将告诉您有关程序集绑定日志查