我正在为自动化调度程序编写一个插件架构,它需要很强大,所以我正在尝试使用ASP.NET / IIS风格的AppDomain - 即每个AppDomain都被视为自己独特的应用程序而没有他们之间共享对象。
我在ApplicationBase
中设置了ConfigurationFile
,ShadowCopyFiles
和AppDomainSetup
。
我为每个插件加载了自动化调度程序中的一个通用程序集 - 它处理加载插件的主程序集,捕获未捕获的异常和日志记录。我发现这种方法存在一些缺点:
通过将ApplicationBase
设置为存储插件的位置,将不再解析公共程序集(位于不同路径中)的任何依赖关系。我通过挂钩AssemblyResolve
事件将其破解为工作,但这会导致其他问题。
公共程序集和插件都可能引用它们自己的同名程序集的副本 - 可能每个都有不同的版本。或者可能是具有相同名称但内容完全不同的程序集。覆盖AssemblyResolve
,将始终首先加载插件的副本。
并不是真的担心这个问题,但是从安全的角度来看,我认识到插件可能会覆盖调度程序的依赖关系,导致它做一些邪恶的事情,或者反映到公共程序集中并获得内部结构
所以我已经决定,或许正确地做到这一点的唯一方法就是不要这样做 - 强制清除分离并且不将任何程序集加载到AppDomain中。我不确定最好的方法是什么,或者即使这是最好的方法。
您怎么看?
答案 0 :(得分:0)
我不确定这是否完全回答了您的问题,但我们在应用程序中有类似的设置,其中我们有独立的子AppDomains和共享DLL的文件夹,我们在不使用AssemblyResolve的情况下取得了成功。
我们的文件结构是:
[PathToApplication]\OurApplication.exe
[PathToApplication]\AddIns\[SharedAssemblies]\*.dll
[PathToApplication]\AddIns\[FirstAddIn]\*.dll
[PathToApplication]\AddIns\[SecondAddIn]\*.dll
方括号中的部分由实际路径替换。
在我们的例子中,共享程序集也由主AppDomain加载,因此我们在主App.config
中设置如下。
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="AddIns\[SharedAssemblies]" />
</assemblyBinding>
</runtime>
确保共享程序集不存在于主可执行文件旁边,或者它将从那里加载它们,并且这样就会在所有AppDomain之间静默地停止在内存中共享DLL。
然后,对于每个加载项的AppDomain,我们对其进行了配置,使基本路径成为加载项文件夹和共享文件夹上方的文件夹,并设置私有bin路径,以便在正确的子文件夹中搜索顺序:
var basePath = @"[PathToApplication]\AddIns";
var configFile = Path.Combine(
basePath,
addInFolder,
addInAssemblyName + ".dll.config");
var binPaths = new [] { "[SharedAssemblyFolder]", addInFolder };
setup = new AppDomainSetup
{
ApplicationBase = basePath,
ConfigurationFile = configFile,
LoaderOptimization = LoaderOptimization.MultiDomain,
PrivateBinPath = string.Join(";", binPaths),
PrivateBinPathProbe = string.Empty,
};
这样它总是首先搜索共享文件夹,所以即使加载项提供了自己的同名DLL,它也会被忽略。
我们在应用程序入口点设置[System.LoaderOptimization(LoaderOptimization.MultiDomain)]
并运行此操作并验证DLL实际上是在内存中共享的(很容易让它稍微出错并默默地阻止这种情况发生)。
希望这在某种程度上有所帮助。