AppDomain.CurrentDomain.SetupInformation.PrivateBinPath为null
当我启动只有一个AppDomain的应用程序时, AppDomain.CurrentDomain.SetupInformation.PrivateBinPath
为null。 即使我在MyApp.exe.config中设置了探测路径,如下所示。
我原以为AppDomain.CurrentDomain.SetupInformation.PrivateBinPath
包含字符串"Dir1;Dir2;Dir3"
。
如何访问MyApp.exe.config中配置的探测路径?
更新
正如Hans Passant指出下面的评论 ,没有为主appdomain设置SetupInformation.PrivateBinPath。 所以上面的方法不起作用。 你有什么建议来模拟融合在探测路径中搜索程序集的方式,或者至少考虑当前应用程序配置中的 ? 我能想到的最好的事情是当前域是主appdomain时手动从App.config读取
(
AppDomain.CurrentDomain.IsDefaultAppDomain()
为true
)。 有没有更好的办法?
更新2
这里需要一些额外的背景信息: Nancy框架的 AppDomainAssemblyTypeScanner.GetAssemblyDirectories()中出现此问题。
南希自动发现并加载第三方模块和其他“插件”。 默认情况下,这应该通过查看探测路径来完成与正常链接的程序集相同的方式(即融合会这样做)。 使用Assembly.Load
(而不是Assembly.LoadFrom
)加载程序集,因此据我所知,加载程序集的所有依赖程序集也必须在应用程序/ appdomain的探测路径中可访问。
如何访问MyApp.exe.config中配置的探测路径
要保持兼容融合的function,您可以阅读有效的配置文件以获取当前的探测路径:
private static string GetProbingPath() { var configFile = XElement.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); var probingElement = ( from runtime in configFile.Descendants("runtime") from assemblyBinding in runtime.Elements(XName.Get("assemblyBinding", "urn:schemas-microsoft-com:asm.v1")) from probing in assemblyBinding.Elements(XName.Get("probing", "urn:schemas-microsoft-com:asm.v1")) select probing) .FirstOrDefault(); return probingElement?.Attribute("privatePath").Value; }
假设你的问题中的配置文件样本它返回:“Dir1; Dir2; Dir3”
不是答案,不适合作为评论
如上所述,默认appdomain不使用AppDomainSetup进行路径探测配置。 而不是这样,探测路径从.appconfig文件中读取,不会暴露给托管代码。
*完整clr上的自托管应用程序可以使用自定义ICustomAppDomainManager(或IHostAssemblyManager)覆盖行为,但这超出了问题的范围。
所以只有三种可能的方法:
- 首先,您可以自己调用
Nancy.Bootstrapper.AppDomainAssemblyTypeScanner.LoadAssemblies(somedir, "*.dll")
- 其次,您可以使用自定义专用bin路径集将nancy主机包装到辅助appdomain。
- 第三:等待https://github.com/NancyFx/Nancy/pull/1846并使用自定义
IResourceAssemblyProvider
。
在任何情况下,您都需要汇编’目录列表。 如果您不想将副本存储为
值,则必须自行解析appconfig文件。
我总是发现最简单的事情就是拦截AppDomain.AssemblyResolve
事件。 然后你可以从任何你想要的地方加载你想要的任何程序集并返回它。 您仍然可以将您的设置存储在appConfig中…如果您特别想使用它,您甚至可以探测路径部分。 需要注意的一点是,使用Assembly.Load加载的程序集不会在与默认加载上下文下加载的程序集相同的加载上下文中结束( https://msdn.microsoft.com/en-us/library/dd153782(v = vs.110).aspx )。 这具有改变后续分辨率(在初始调用Assembly.Load之后)的类型和程序集分辨率的方式的效果。 因此,您可能希望拦截AppDomain.TypeResolve
以及AssemblyResolve
…并且您将要缓存从AssemblyResolve加载的程序集…否则后续分辨率可能实际上再次加载相同的程序集(取决于您究竟调用的方式) Assembly.Load)
如果这是程序集未加载的问题,我发现有效工作的一种方法是使用AppDomain.AssemblyResolve事件,当appdomain无法加载程序集时会触发该事件…
使用AppDomain.AssemblyResolve事件
例如
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(LoadManually); private Assembly LoadManually(object sender, ResolveEventArgs args) { .... return Assembly.LoadFrom(whereEverYouLike); }
受g.pickardou解决方案的启发,我创建了无需引用System.Xml.Linq的函数:
private static string GetProbingPath() { var xmlDoc = new XmlDocument(); xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile); var privatePathAttribute = xmlDoc.SelectSingleNode("/*[name()='configuration']/*[name()='runtime']/*[name()='assemblyBinding']/*[name()='probing']/@privatePath"); return (privatePathAttribute as XmlAttribute)?.Value; }