解决MSB3247 - 发现同一依赖程序集的不同版本之间的冲突

439

当使用msbuild编译一个.NET 3.5解决方案时,会出现此警告。

有时候可以使用NDepend来帮助解决问题,但在这种情况下它没有提供更多的细节。就像Bob一样, 我最终不得不打开ILDASM中的每个程序集,直到找到引用旧版本相关程序集的那个程序集。

我尝试使用VS 2010 Beta 2中的MSBUILD(因为Connect文章指出这个问题已经在CLR的下一个版本中修复了),但也没有提供更多的细节(也许是Beta 2之后修复的)。

是否有更好(更自动化)的方法?


2
在我的情况下,我只需要确保解决方案中的所有项目都运行相同版本的NuGet包(可以简单地将所有项目更新到最新版本)。 - Michael
请参见https://dev59.com/XmAf5IYBdhLWcg3wVxYp。 - SteveC
16个回答

587

将“MSBuild项目构建输出详细程度”更改为“详细”或更高。要执行此操作,请按照以下步骤进行:

  1. 打开选项对话框(工具 -> 选项...)。
  2. 在左侧树中选择项目和解决方案节点,然后选择生成和运行
    • 注意:如果这个节点没有显示出来,请确保对话框底部的复选框显示所有设置已被选中。
  3. 在出现的工具/选项页面上,根据您的版本将MSBuild项目构建输出详细程度级别设置为适当的设置:

  4. 构建项目并查看输出窗口。

查看MSBuild消息。 从中产生MSB3247的任务ResolveAssemblyReferences应该可以帮助您调试此特定问题。

我的具体情况是对SqlServerCe的引用不正确。请参见以下内容。 我有两个引用了两个不同版本SqlServerCe的项目。我转到旧版本的项目,删除了引用,然后添加了正确的引用。

Target ResolveAssemblyReferences:
    Consider app.config remapping of assembly "System.Data.SqlServerCe, ..." 
        from Version "3.5.1.0" [H:\...\Debug\System.Data.SqlServerCe.dll] 
        to Version "9.0.242.0" [C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\PublicAssemblies\System.Data.SqlServerCe.dll]
        to solve conflict and get rid of warning.
    C:\WINDOWS\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets : 
        warning MSB3247: Found conflicts between different versions of the same dependent assembly.

你不需要打开每个程序集来确定引用程序集的版本。

  • 您可以检查每个引用的属性。
  • 打开项目属性并检查引用部分的版本。
  • 使用文本编辑器打开项目。
  • 使用.Net反编译器。

6
您的解决方案看起来对我很好,但我认为并不总是有用使用“参考文献”部分查看版本号。我经常看到VS向我“撒谎”,即使用的版本与.csproj文件中实际提到的版本不同。 - David Gardiner
6
我同意您对使用C#项目时“虚假”的说法。 根据我的经验,C#项目可能会混淆引用的版本和实际编译/链接的版本。 当发生这种情况时,我会清理解决方案,手动删除bin和obj文件夹,然后删除%APPDATA%中的临时项目程序集。 重新构建解决方案通常可以解决问题。(VB很少遇到这个具体问题。) - AMissico
56
教导人们实际使用“输出窗口”是获胜的关键。构建操作不仅限于按下F5和查看错误列表窗口。 - JJS
2
正如ErikHeemskerk在他的回答中提到的那样,在Visual Studio 2010中,您需要将输出详细程度设置为详细才能看到ResolveAssemblyReferences的输出。 - Robin Clowers
16
提示:要在冗长的生成输出中找到确切位置,请将文本复制到文本编辑器中,搜索“Found conflicts between different versions of the same dependent assembly.”。(意思是:在生成输出中查找“Found conflicts between different versions of the same dependent assembly.”以找到精确位置。) - Contango
显示剩余10条评论

142

Mike Hadlow发布了一个小控制台应用程序,名为AsmSpy,它很好地列出了每个程序集的引用

Reference: System.Net.Http.Formatting
        4.0.0.0 by Shared.MessageStack
        4.0.0.0 by System.Web.Http

Reference: System.Net.Http
        2.0.0.0 by Shared.MessageStack
        2.0.0.0 by System.Net.Http.Formatting
        4.0.0.0 by System.Net.Http.WebRequest
        2.0.0.0 by System.Web.Http.Common
        2.0.0.0 by System.Web.Http
        2.0.0.0 by System.Web.Http.WebHost

这是一个比依赖于MSBuild输出更快找到警告MSB3247底部的方式。


1
AsmSpy非常棒,你只需要记住要寻找对第三方DLL的引用版本不匹配的情况。通常,对标准库的引用版本不匹配不会导致这些警告(你会经常看到它们)。 - Tod Thomson
15
谢谢你们的好话 :) - Mike Hadlow
你刚刚为我节省了几个小时的工作时间!阅读详细输出确实有所帮助,但一旦我使用了你的工具进行验证,就变得非常容易了。 - Norman H
从底部开始阅读输出,直到找到第一个冲突为止。.NET程序集往往排在前面,因此这将帮助您快速找到最有可能的罪魁祸首。 - N-ate
这个工具真是太棒了!挖了2个小时,找到这个神奇的答案,指向这个神奇的项目,只用了5分钟!感谢之情难以言表! - rynkadink
显示剩余2条评论

24

有时候 @AMissico 的回答不够详细。在我的情况下,我找不到“输出”窗口中的错误,所以我决定创建一个日志文件并分析它,具体步骤如下:

  1. 将生成日志保存至文件... https://msdn.microsoft.com/zh-cn/library/ms171470.aspx

    msbuild MyProject.proj /fl /flp:logfile=MyProjectOutput.log;verbosity=detailed

  2. 查找文本:warning MS... 或指定的警告信息:(例如第9293行)Found conflicts between different versions...,而冲突错误的完整细节将出现在此消息之上(例如第9277行)There was a conflicts between... Find the error message

Visual Studio 2013


21

我发现(至少在Visual Studio 2010中)您需要将输出详细程度设置为“详细”才能找到问题。

可能是因为我的问题是一个之前是GAC引用的引用,在重新安装我的机器后不再是这种情况了。


1
转到工具->选项->项目和解决方案->生成和运行以设置输出详细程度。 - Farshid

9

我遇到了同样的错误,而其他答案也无法解决。我发现我们可以使用“Consolidate”NuGet包。

  1. 右键单击解决方案
  2. 点击管理Nuget包
  3. 转到合并选项卡并更新为相同的版本。

7
此警告是为默认的ASP.NET MVC 4 beta生成的。 请参见此处 在任何情况下,您都可以通过手动编辑项目的.csproj文件来消除此警告。 修改:Reference Include="System.Net.Http" 更改为:Reference Include="System.Net.Http, Version=4.0.0.0"

1
我按照这个方法做后,错误消失了。仍然不知道为什么,我使用VS2010开始了一个MVC4项目,然后迁移到了VS2012。但是,添加版本属性后,错误消失了。谢谢。 - MaiOM

6
使用依赖关系阅读器
使用 dep.exe,您可以列出整个文件夹的所有嵌套依赖项。 结合像grep或awk这样的Unix工具,它可以帮助您解决问题。
查找被引用多个版本的程序集。
$ dep | awk '{ print $1 " " $2; print $4 " " $5 }' | awk '{ if (length(versions[$1]) == 0) versions[$1] = $2; if (versions[$1] != $2) errors[$1] = $1; }  END{ for(e in errors) print e } ' 
System.Web.Http            

这个晦涩的命令行先运行了dep.exe,然后将输出两次导向awk,以
  • 将父项和子项放在单个列中(默认情况下,每行包含一个父项和一个子项,以表达该父项依赖于该子项的事实)
  • 然后使用关联数组进行一种“分组”

理解此程序集如何被引入您的bin目录

$ dep myproject/bin | grep -i System\.Web\.Http
MyProject-1.0.0.0 >> System.Web.Http.Web-5.2.3.0 2 ( FooLib-1.0.0.0 )
MyProject-1.0.0.0 >> System.Web.Http.Web-4.0.0.0 2 ( BarLib-1.0.0.0 )
FooLib-1.0.0.0 > System.Web.Http.Web-5.2.3.0 1
BarLib-1.0.0.0 > System.Web.Http.Web-4.0.0.0 1 

在这个例子中,这个工具会告诉你 System.Web.Http 5.2.3 来自于你对 FooLib 的依赖,而版本 4.0.0 则来自于 BarLib。
然后你可以选择:
  • 说服库的所有者使用相同的版本
  • 停止使用其中之一
  • 在你的配置文件中添加绑定重定向以使用最新版本

如何在 Windows 中运行这些东西

如果你没有类Unix的shell,你需要下载一个才能运行 awk 和 grep。尝试以下任意一种方法。 这段文本列出了几个软件组合,包括使用 cmder、awk 和 dep.exe,使用 gitbash、awk 和 dep.exe,以及使用 cygwin 和 dep.exe。每个软件名称都是超链接。

4
我也遇到了这个问题并使用了AMissico的建议来发现问题(虽然必须将详细程度设置为详细)。
然而,找到罪魁祸首后,问题实际上非常简单。
背景: 我将我的项目从VS2008升级到VS2010。在VS2008中,目标框架是3.5,当我将它带到VS2010时,我将其切换到4(完整版)。我还升级了一些第三方组件,包括Crystal报告。
事实证明,大多数系统引用都指向版本4.0.0.0,但有几个没有自动更改(System和System.Web.Services),仍然在查看2.0.0.0。Crystal报告引用了4.0.0.0,因此冲突就发生在这里。只需将光标放在解决方案资源管理器中的第一个System库处,按下光标并查找任何对2.0.0.0的引用,删除并重新添加更新的4.0.0.0版本即可解决问题。
奇怪的是,大多数引用已经正确更新,如果不是因为Crystal报告,我可能永远不会注意到...

3

快速解决:

右键点击解决方案 -> 管理解决方案的 NuGet 包 -> 在合并下,您可以看到是否安装了不同版本的相同包。卸载不同的版本并安装最新版本。


这应该是最佳答案。整合 NuSet 到整个解决方案中,让您可以看到问题所在,并且无需任何问题即可更新它们。 - matendie
这是对这个问题最简单的答案,感谢你的帮助。 - Jean Jimenez

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接