进行插件式编程的时候,常常性地弹出这么个东西找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040),每每这种问题特别难以解决,搞定了一个还要出另一个。得研究一下怎么处理。html
这里提示须要加载一个4.2.0.0版本的dll,我先看看文件夹下面有没有对应的dll,查看文件dll的详细信息。
git
这个版本号4.6.27818.1和4.2.0.0也差的有点太远了吧,是这个问题?其实不是的,这个地方显示的版本和程序集的版本不是一回事。github
.NET程序有不少版本的说法,官方对这个有解释,经过文件管理器得到的版本是AssemblyFileVersion
,而程序集加载器定位的版本使用的是AssemblyVersion
,这两个东西彻底不是一回事。经过右键,咱们看不到AssemblyVersion,比较简单的方式,能够经过Powershell脚原本查看程序集版本。shell
ls *.dll -r | ForEach-Object { try { $_ | Add-Member NoteProperty FileVersion ($_.VersionInfo.FileVersion) $_ | Add-Member NoteProperty AssemblyVersion ( [Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version ) } catch {} $_ } | Select-Object Name,FileVersion,AssemblyVersion
能够看到,我这边的程序集是4.2.0.1版本的,不是4.2.0.0版本的,所以,程序集不能正常加载。
编程
我本身的项目是使用nuget进行包管理的,引用的包的版本号是4.5.3(又多一个版本...),程序集版本是4.2.0.1。我找遍了整个项目,都没有找到我dll项目中关于4.2.0.0版本的引用,苦思良久,打盹的时候突然想起来,是否是那个exe的问题?安全
个人主exe程序是使用.NET Framework 4.6.1进行编译,而后单独编译dll做为插件放入一个文件夹,由exe程序进行加载。那有多是exe引用了4.2.0.0这个版本,或者是其余dll插件引用了这个版本,形成版本不兼容。app
这种状况能够有不少种解决方案,这篇文章写的很是详细,推荐读一读。而我这里使用了最简单也是做者比较推荐的办法,程序集引用的绑定重定向。工具
使用这个方法有一个前提,你须要彻底了解其余程序引用这个程序版本的时候不会出问题,通常小版本号的变更,是相对比较安全的。性能
一直以来,我写.NET Framework程序貌似就不多有这种问题,是由于微软会自动给程序设置重定向,咱们能够经过在项目上右键,点选自动生成绑定重定向。
ui
以后,会出现一个app.config
文件,它会在生成程序的时候,变成程序名称.dll.config
的形式,里面大概是这个样子的:
<?xml version="1.0" encoding="utf-8"?> <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" /> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
能够发现,这个东西对咱们引用的版本内容进行了限制,强制某个范围内的版本重定向为一个固定的版本号。不过,虽然dll中已经有这个内容,可是exe不会理会它的,它只会看本身主程序的.exe.config文件。因此咱们须要作的,就是把这一个部份内容搬到主程序的.exe.config
中。
修改后从新运行,而后有又提示找不到System.Buffers.dll了,如法炮制,问题解决。
有时候,经过这个方法找下去,处理完了,也不必定可以解决,由于这个错误提示的是“未能加载文件或程序集或它的某一个依赖项。”,也多是某个引用的依赖项出了问题,这样就不是很好找了。
好在.NET提供了一个程序集绑定日志的工具,能够帮助咱们查看绑定的问题。通常状况下,这个东西是关闭的,系统会提示:
警告: 程序集绑定日志记录被关闭。 要启用程序集绑定失败日志记录,请将注册表值 [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD)设置为 1。 注意: 会有一些与程序集绑定失败日志记录关联的性能损失。 要关闭此功能,请移除注册表值 [HKLM\Software\Microsoft\Fusion!EnableLog]。
调试的话,能够打开这个注册表键值。或者简单点,直接使用Fuslogvw.exe
(程序集绑定日志查看器),用管理员帐号启动,在设置中设置好记录的日志信息,而后就能够记录了,详细的使用方法,见这里。就能看到详细的信息了,能够帮助咱们深刻分析内部绑定的问题。(用完记得关,有性能损失。)
=== 预绑定状态信息 === 日志: DisplayName = System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 (Fully-specified) 日志: Appbase = file:///C:/Temp/360zip$Temp/360$0/ 日志: 初始 PrivatePath = NULL 调用程序集: DependencyWalker, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null。 === 日志: 此绑定从 default 加载上下文开始。 日志: 未找到应用程序配置文件。 日志: 使用主机配置文件: 日志: 使用 C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config 的计算机配置文件。 日志: 策略后引用: System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51 日志: 相同的绑定已出现过,因 hr = 0x80070002 而失败。
说到dll的引用,就有必要提一提很是有名的一个工具Dependency Walker,它能够查看PE文件的引用状况,可是这个程序好久没有更新了,对.NET很不友好。我找了一下,发现几个替代:
这个工具能够认为是Dependency Walker的升级版,能够查看PE文件的引用信息,对.NET也能够支持,不过看的信息太少了,也没法显示缺失的状况。
这个工具是专门为.NET设计的,能够查看程序集的引用状况,我删除了我插件的几个dll,而后看就是这个样子,一目了然,版本号也很是清楚。
经过这些工具,能够帮咱们找一找究竟是dll的问题,也许会对“试图加载格式不正确的程序。”、“引用不匹配。”等引用相关问题有所帮助。
这些工具处理的大可能是静态引用,对于使用动态引用的,通常是不支持的。
插件式编程极大加强了程序的拓展能力,不过,在处理程序集引用的时候,须要很是当心不一样插件带来的引用问题。程序设计的时候,可使用不一样文件夹隔离不一样的插件dll,并经过一些技巧来加载(能够查看以前的文章)和隔离,这样,就能够避免出现不匹配的错误了。