《西游记》中真假美猴王让人着实难以区分,但是我们熟知了其中的细节也不难把他们剥去表象分别出来。对问题不太关心的可以直接调到文中关于.Net文件版本的介绍

问题

最近在编译AKKA.net 时出现了一个问题:Newtonsoft.Json.dll 冲突.

C:\Program Files (x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(1819,5): warning MSB3243: No way to resolve conflict between "Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed" and "Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed". Choosing "Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed" arbitrarily.

Consider app.config remapping of assembly "Newtonsoft.Json, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed" from Version "4.5.0.0" [C:\Program Files (x86)\Microsoft Visual Studio 12.0\Blend\Newtonsoft.Json.dll] to Version "7.0.0.0" [D:\TestProjects\GitHub\akka.net\src\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll] to solve conflict and get rid of warning.

解决

分析问题

在VisualStudio给出的错误提示中,第一句话着实让人摸不着头脑。还好第二句给出冲突Dll文件的具体路径。但是奇怪的的是明明通过以下命令:

获取的Newtonsoft.Json.dll 应该是 “7.0.1”版本,怎么出来让remaping 到 “7.0.0”版本。

奇怪啊!!

核实Nuget到Newtonsoft.Json.dll

打开Dll文件核实下:

双击“1 [Neutral]”图标,将会打开dll程序集的详细信息如下:

原来Assembly的确是“7.0.0.0”

那好吧,我们再来看下Blend 下的同名文件

 

Blend文件夹下的Newtonsoft.Json.dll

Assembly Version 4.5.0.0 这和上面7.0.0.0完全不一样啊,VisualStudio(VS)怎么会把他们混淆了??

尝试解决

让我们来猜下原因吧,那是不是VS找不到具体的7.0.0 的Dll呢,然后就找到了4.5.0 的DLL,结果就…??

打开报错的项目,先卸载项目,然后才可以编辑查看项目文件:

打开项目

 

发现有两个地方出现了Newtonsoft.Json :

在查阅过<choose>这个不常用节点的用法后,我猜这个是因为这个节点导致,于是直接Ctrl+H 替换成于Reference相同的路径,编译,成功通过

 

问题相关知识

上一堆截图,到底要干嘛呢?相信一定有人会疑惑。

对,上面折腾半天的目的就是为了找出以下几个关于.Net程序集版本至关重要的三大版本,第一次接触一定很好奇(也许是郁闷,因为出问题闹心啊)。

三个重要的.Net 程序集版本

在.Net中有三个重要的版本信息,因为经常混淆,所以要大家注意:

// Assembly mscorlib, Version 2.0.0.0
[assembly: AssemblyFileVersion("2.0.50727.3521")]
[assembly: AssemblyInformationalVersion("2.0.50727.3521")]
[assembly: AssemblyVersion("2.0.0.0")]

版本信息的四部分,我们约定为Major Version(主版本), Minor Version(次版本), Build(编译版本), and Revision(修订版本)

AssemblyFileVersion

通常我们会手动设置 AssemblyFileVersion 中的Major和Minor 去体现程序集的版本,Build 和(或者) Revision 这两个一般是由Build工具在每次编译程序集时自动增加的。 我们可以用AssemblyFileVersion来作为程序集的唯一标识。(调试的时候我们就可以根据这个版本号找到相应dll,)

 

在项目开发中一般我们会用ChangeList(变更集)号去生成AssemblyFileVersion 的Build和Revision两部分。这样就很方便从dll找到相应的源代码变更集。省去了自己单独去记录发布的dll和源代码对应关系的繁琐事项。

AssemblyFileVersion 存储在Win32的版本资源中,所以可以通过资源浏览器(右击属性)查看程序集的相应AssemblyFileVersion

The CLR does not care about nor examine the AssemblyFileVersion.

AssemblyInformationalVersion

AssemblyInformationalVersion 目的是用于整个产品(某个dll或者exe)能够有一个一致的(coherent)版本。这个产品可能含有很多个程序集,而且这些程序集可能有不同的版本标识策略或者根本不是同一个团队开发的。

“For example, version 2.0 of a product might contain several assemblies; one of these assemblies is marked as version 1.0 since it’s a new assembly that didn’t ship in version 1.0 of the same product. Typically, you set the major and minor parts of this version number to represent the public version of your product. Then you increment the build and revision parts each time you package a complete product with all its assemblies.”

        — Jeffrey Richter, CLR via C# (Second Edition) p. 57

 

The CLR does not care about nor examine the AssemblyInformationalVersion.

AssemblyVersion

AssemblyVersion 存储在AssemblyDef的元数据列表清单,任何引用该AssemblyVersion 版本的dll(.exe)。

The AssemblyVersion is used by the CLR to bind to strongly named assemblies.(CLR唯一关心的版本)这一点至关重要。

只有AssemblyVersion版本完全一致的(匹配的)强命名程序集,才能编译成功。例如,如果你引用了一个1.0.0.0的强命名A.dll,编译后,你将A.DLL升级到了1.0.0.1.那么,不好意思,你的程序将会失败,那就没有办法了吗?有可以参考Assembly Binding Redirection 来做DLL重定向。

Assembly Version : This is the version number used by framework during build and at runtime to locate, link and load the assemblies. When you add reference to any assembly in your project, it is this version number which gets embedded. At runtime, CLR looks for assembly with this version number to load. But remember this version is used along with name, public key token and culture information only if the assemblies are strong-named signed. If assemblies are not strong-named signed, only file names are used for loading.

 

小心修改AssemblyVersion

当别的开发人员正在引用你发布的程序集是,你应该非常小心的去修改这些程序集的AssemblyVersionAssemblyVersion的任何改动都意味着开发者不得不重新编译应用程序(或者相应的dll)而不是简单的直接文件覆盖(新版本dll直接覆盖就版本dll)。

  • 如果要保证当前发布的dll向后兼容,请不要修改AssemblyVersion。
  • 如果你有突破性的修改(脱胎换骨的大改动),那请修改AssemblyVersion。

 

补充,Redirect Binding的问题(程序集冲突解决方法,不含修改文件路径的方法)

自动重定向

Starting with Visual Studio 2013, when you compile apps that target the .NET Framework 4.5.1, binding redirects may be automatically added to the app configuration file to override assembly unification. Binding redirects are added if your app or its components reference more than one version of the same assembly, even if you manually specify binding redirects in the configuration file for your app. The automatic binding redirection feature affects traditional desktop apps and web apps that target the .NET Framework 4.5.1, although the behavior is slightly different for a web app. You can enable automatic binding redirection if you have existing apps that target previous versions of the .NET Framework, or you can disable this feature if you want to keep manually authored binding redirects.

在项目文件(.csproj or .vbproj)的<PropertyGroup>标签下添加<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>可以让VisualStudio自动重定向到相应的DLL。

示例:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{123334}</ProjectGuid>
...
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
...
</Project>

 

Remaping来重定向

 

<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed"/>
<bindingRedirect oldVersion="0.0.0.0-4.5.0.0" newVersion="6.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>

注意:

  • <bindingRedirect>标签中属性newVersion 和oldVersion 都是AssemblyVersion。
  • 在应用程序配置文件(web.config或者App.config)中<runtime> 标签是在<configuration></configuration> 标签内.
  • xmlns 属性表示相应 XML namespace. xmlns="schemas-microsoft-com:asm.v1" 是程序集开发人员避免标签冲突而添加的。
  • oldVersion 中可以包含所有的兼容的dll版本
  • publicKeyToken 是该程序集公钥. 通过sn -T assembly_file_name命令可以获取到也可同Reflector查看.

 

 

总结

有的同仁总觉得.Net简单,GC帮我做了好多内存管理工作,我们就可以随心所欲,为所欲为。且不知任何技术都有他不可告人的软肋,广告总是大篇幅的说着自己的完美哪有功夫给大家展示自己的不足(当然这里很多时候涉及到了设计准则哲学,如框架设计会优先考虑20%的经常使用功能,而暂缓考虑其他的80%不常用的功能)。

所以学习一门技术一定要知道他的底层原理和关键点。知道的越多,你被坑的概率就会越少,效率就越高。

 

参考

Newtonsoft.Json Assembly Conflict

Choose Element (MSBuild)

Assembly Versioning in .NET

Assembly Binding Redirection

《CLR Via C#》

.Net中DLL冲突解决(真假美猴王)的更多相关文章

  1. Eclipse中Egit冲突解决

    Eclipse中Egit冲突解决 Git 作为进来最流行的分布式版本控制软件来说应用的十分广泛.EGit就是一款Eclipse上的Git插件.在使用Egit提交项目时,有时会产生冲突,需要对代码进行m ...

  2. 团队开发中Git冲突解决

    正常来说我们团队协作开发过程中,冲突是常有的事,下面介绍下本人在开发中的解决办法. 冲突的主要原因就是由于我们开发人员在分支的同一位置写入了不一样的代码,然后合并到主干上导致我们冲突. 方法: 当冲突 ...

  3. git在idea中的冲突解决(非常重要)

    1.什么是冲突 冲突是指当你在提交或者更新代码时被合并的文件与当前文件不一致.读起来有点绕,结合下面的案例理解. 从上面对冲突的定义来看,冲突时发生在同一个文件上的. 2.生产上冲突的场景 常见冲突的 ...

  4. maven中jar冲突解决

    Maven中jar包冲突是开发过程中比较常见而又令人头疼的问题,我们需要知道 jar包冲突的原理,才能更好的去解决jar包冲突的问题.本文将从jar包冲突的原理和解决两个方面阐述Maven中jar包冲 ...

  5. HashMap中的散列函数、冲突解决机制和rehash

    一.概述 散列算法有两个主要的实现方式:开散列和闭散列,HashMap采用开散列实现. HashMap中,键值对(key-value)在内部是以Entry(HashMap中的静态内部类)实例的方式存储 ...

  6. Idea中Git的使用和两种类型的冲突解决

    一.Git冲突解决 在idea开发工具中使用Git时,主要用到的快捷按钮如下五个:   这五个按钮的使用说明及在idea中如何配置和使用git可参考https://github.com/DayThin ...

  7. SVN:冲突解决 合并别人的修改

    在项目中,基本不可避免多个人同时参与一个项目,因此就可能会出现多个人同时修改一个文件的情况,就不可避免的会出现冲突.svn已经很聪明了,如 果你和别人对于同一个文件的修改之间不存在重叠(比如你在文件最 ...

  8. 三步快速解决dll冲突问题

    最近在推广应用我们的分布式服务网关(Web Api):业务组大部分对外的业务逻辑以HSF服务或者自定义扩展插件的方式,注册并发布到分布式服务网关中,统一对外提供WebApi服务.临时介绍下我们的分布式 ...

  9. C# 如何解决 引用的两个同名同版本的DLL冲突

    离职后来到现在这家公司,在这几天接到一个项目要求是要通过淘宝聚石塔API来抓取公司的订单流水.按理说这项任务不算很难,但是,你也知道,壮士出征往往死在离出发地不远的地方.现在我们来研究一下为什么会导致 ...

随机推荐

  1. Bootstrap3系列:下拉菜单

    1.引用Bootstrap 示例引用的Bootstrap版本:v3.3.7 <script src="~/Scripts/jquery-2.2.4.min.js">&l ...

  2. Livecoding.tv 现正举行iOS及Android App设计比赛

    近日,Livecoding.tv, 一个为世界各地的程序员提供在线实时交流的平台,在其网站上发布了一篇通知, 宣布从4月15日至5月15日,会为iOS和Android的开发者举办一场本地移动app设计 ...

  3. PHP 面向对象编程和设计模式 (3/5) - 单例模式和工厂模式

    PHP高级程序设计 学习笔记 2014.06.11 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容 ...

  4. jQuery 插件-(初体验一)

    1.jquery有2个扩展方法: jquery.fn.extend=jquery.prototype.extend jquery.extend (两者的区别放在后面文章说) 2.具体实例结构: //创 ...

  5. 新项目的CQRS设计

    刚换了个工作,闲话不说了.前两天开始一个新项目,大概是一个任务管理系统,由使用者来选取任务,执行任务,反馈完成,我大概做了些设计,本来是打算看能不能在新公司铺垫一下DDD,不过后来这块功能没分到我这, ...

  6. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

  7. Oracle基础维护02-表、主键、索引、表结构维护手册

    目录 一.项目新建表.主键.索引注意事项 二.举例说明建表.主建.索引的操作方法 2.1 设定需求如下 2.1.1 查询数据库有哪些表空间 2.1.2 本文档假设数据库有这两个业务用户的表空间 2.2 ...

  8. Cesium原理篇:Property

    之前主要是Entity的一个大概流程,本文主要介绍Cesium的属性,比如defineProperties,Property(ConstantProperty,CallbackProperty,Con ...

  9. 看我是如何处理自定义线程模型---java

    看过我之前文章的园友可能知道我是做游戏开发,我的很多思路和出发点是按照游戏思路来处理的,所以和web的话可能会有冲突,不相符合. 来说说为啥我要自定义线程模型呢? 按照我做的mmorpg或者mmoar ...

  10. Navisworks Api Tool

    用Google 翻译的..做个参考 None  无有效的选择  Select  选择 SelectBox 选择框 RedlineFreehand  红线写意 RedlineLine 红线线 Redli ...