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

. net 3.5解决方案在使用msbuild编译时出现此警告。

有时NDepend可能会有所帮助,但在这种情况下,它没有提供任何进一步的细节。我最终不得不求助于在ILDASM中打开每个程序集,直到我找到一个引用依赖程序集的旧版本。

我确实尝试使用VS 2010 Beta 2的MSBUILD(连接文章指出这在CLR的下一个版本中得到了修复),但也没有提供更多的细节(可能是在Beta 2后修复的)。

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

213295 次浏览

将“MSBuild项目构建输出详细信息”更改为“详细信息”或以上。要做到这一点,请遵循以下步骤:

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

      • 在VS2012, VS2013或VS2015上诊断(这些版本中的消息你应该使用“Detailed”,但这是完全错误的,你应该使用“诊断”)
      • 详细的当你在VS2010
      • 正常的在VS2008或更老版本中就足够了。
      • 李< / ul > < / >
      • 构建项目并在输出窗口中查看。

检查MSBuild消息。ResolveAssemblyReferences任务,这是MSB3247起源的任务,应该帮助您调试这个特定的问题。

我的具体情况是对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.

您不必打开每个程序集来确定引用程序集的版本。

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

我发现(至少在Visual Studio 2010中),您需要将输出详细信息设置为至少详细的,以便能够发现问题。

这可能是我的问题是一个参考,以前是一个GAC参考,但这不再是我的机器重新安装后的情况。

我也有这个问题,并使用了AMissico的建议,发现了这个问题(尽管必须将冗长级别设置为详细。

在找到罪魁祸首后,问题其实很简单。

< p >背景: 我把我的项目从VS2008升级到VS2010。在VS2008中,目标框架是3.5,当我把它带入VS2010时,我把它切换到4 (Full)。我还升级了一些第三方组件,包括水晶报表

结果发现大多数系统引用指向4.0.0.0版本,但有几个没有自动更改(System和System. web . services),仍然指向2.0.0.0版本。水晶报告引用4.0.0.0,所以这是冲突发生的地方。只需将光标放在解决方案资源管理器中的第一个System库上,向下移动列表并查找对2.0.0.0的任何引用,删除并重新添加新的4.0.0.0版本就可以了。

奇怪的是,大多数参考文献都被正确更新了,如果不是水晶报告,我可能永远都不会注意到……

ASP。NET构建管理器通过按字母顺序浏览文件夹来构建网站,对于每个文件夹,它会找出它的依赖项并首先构建依赖项,然后再构建选定的文件夹。

在这种情况下,有问题的文件夹是~/Controls,在开始时被选择构建,出于未知的原因,它将一些控件构建为一个单独的程序集,而不是像其他控件一样在同一个程序集中(似乎与某些控件依赖于同一文件夹中的其他控件的事实有关)。

然后构建的下一个文件夹(~/File-Center/Control)依赖于根文件夹~/,根文件夹~/依赖于~/Controls,所以文件夹~/Controls再次被构建,只是这次分离到自己程序集的控件现在与其他控件连接到相同的程序集,分离的程序集仍然被引用。

因此此时至少有2个程序集具有相同的控件,构建失败。

虽然我们仍然不知道为什么会发生这种情况,我们能够通过将Controls文件夹名称更改为ZControls来解决它,这样它就不会在~/File-Center/Control之前构建,只在之后构建,这样它就应该被构建。

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底部的更快方法。

默认ASP。NET MVC 4测试版 在这里看到的 < / p >

类型可以消除此警告的任何强制转换

.csproj文件

修改……:参考Include="System.Net.Http"

阅读......:参考Include="System.Net。Http、版本= 4.0.0.0"

正如前面提到的在这里,你需要删除未使用的引用,警告就会消失。

最简单的方法是不考虑(内部)依赖关系:

  1. 打开“解决方案资源管理器”。
  2. 点击“显示所有文件”
  3. 扩大“引用”
  4. 您将看到一个(或多个)引用与其他引用的图标略有不同。通常情况下,它会有一个黄色的方框,建议你记下它。把它拿掉。
  5. 重新添加引用并编译代码。
  6. 这是所有。

在我的例子中,MySQL引用有一个问题。以某种方式,我可以在所有可用引用的列表下列出它的三个版本。我遵循了上面的方法1到6,它对我很有效。

我做了一个基于Mike Hadlow应用:AsmSpy的应用程序。

我的应用程序是一个带有GUI的WPF应用程序,可以从我的家庭web服务器下载:AsmSpyPlus.exe

代码可在:GitHub处获得

Gui Sample

有时候@AMissico的答案是不够的。在我的例子中,我在Output窗口中找不到错误,所以我决定创建一个日志文件并分析它,执行以下步骤:

  1. 将生成日志保存到文件中…https://msdn.microsoft.com/en-us/library/ms171470.aspx

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

  2. 找到文本:warning MS...或特定的警告信息:(例如第9293行)Found conflicts between different versions...和冲突错误的完整细节将在此消息(例如第9277行)There was a conflicts between...的上面 查找错误信息

Visual Studio 2013

使用依赖项阅读器

使用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

  • 将父节点和子节点放在一列中(默认情况下,每行包含一个父节点和一个子节点,以表示这个父节点依赖于那个子节点)
  • 然后使用关联数组进行一种“group by”

了解这个组件是如何被拉进你的箱子的

$ 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,你需要在运行__abc0和grep之前下载一个。试试下面的一种方法

  • __abc0 + __abc1 + __abc2
  • __abc0 + __abc1 + __abc2
  • __abc0 + __abc1

我也犯了同样的错误,无法用其他答案来计算。我发现我们可以“巩固”NuGet包。

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

快速修复:

右键单击解决方案->管理解决方案->的NuGet包在巩固下,你可以看到是否有相同包的不同版本被安装。卸载不同版本,安装最新版本。

Visual Studio for Mac Community新增:

由于AMissico的回答需要更改日志级别,而ASMSpy和ASMSpyPlus都不能作为跨平台解决方案,下面是Visual Studio for Mac的一个简短补充:

https://learn.microsoft.com/en-us/visualstudio/mac/compiling-and-building

它在Visual Studio社区→Preferences…→项目→构建日志→冗长

如果您有resharper,删除解决方案中所有未使用的参考。

有时AutoGenerateBindingRedirects是不够的(即使有GenerateBindingRedirectsOutputType)。搜索所有There was a conflict条目并逐个手动修复它们可能很乏味,所以我写了一小段代码来解析日志输出并为你生成它们(转储到stdout):

// Paste all "there was a conflict" lines from the msbuild diagnostics log to the file below
const string conflictFile = @"C:\AssemblyConflicts.txt";


var sb = new StringBuilder();
var conflictLines = await File.ReadAllLinesAsync(conflictFile);
foreach (var line in conflictLines.Where(l => !String.IsNullOrWhiteSpace(l)))
{
Console.WriteLine("Processing line: {0}", line);


var lineComponents = line.Split('"');
if (lineComponents.Length < 2)
throw new FormatException("Unexpected conflict line component count");


var assemblySegment = lineComponents[1];
Console.WriteLine("Processing assembly segment: {0}", assemblySegment);
var assemblyComponents = assemblySegment
.Split(",")
.Select(kv => kv.Trim())
.Select(kv => kv.Split("=")
.Last())
.ToArray();


if (assemblyComponents.Length != 4)
throw new FormatException("Unexpected conflict segment component count");


var assembly = assemblyComponents[0];
var version = assemblyComponents[1];
var culture = assemblyComponents[2];
var publicKeyToken = assemblyComponents[3];


Console.WriteLine("Generating assebmly redirect for Assembly={0}, Version={1}, Culture={2}, PublicKeyToken={3}", assembly, version, culture, publicKeyToken);
sb.AppendLine($"<dependentAssembly><assemblyIdentity name=\"{assembly}\" publicKeyToken=\"{publicKeyToken}\" culture=\"{culture}\" /><bindingRedirect oldVersion=\"0.0.0.0-{version}\" newVersion=\"{version}\" /></dependentAssembly>");
}


Console.WriteLine("Generated assembly redirects:");
Console.WriteLine(sb);

提示:使用MSBuild二进制和结构化日志查看器并仅为发出警告的项目中的冲突生成绑定重定向(也就是说,仅通过那些there was a conflict行到上面代码[AssemblyConflicts.txt]的输入文本文件)。