Description:使用命令行编译项目时,只会拷贝直接引用的二进制dll到项目输出文件夹,不会拷贝间接引用的。例如同一解决方案下有A,B两个项目,A项目引用log4net,B项目引用A项目。使用VS编译时会把log4net.dll拷贝到B项目的bin目录,但是简单的使用MSBuild b.csproj /p:Configuration:Release并不会拷贝log4net.
Analysis:从最表面入手,没有拷贝就让他拷贝。查看MSDN,得知有Copy task可以用,实际上msbuild所有的步骤都定义在csproj文件和MSBuild .Targets 文件里边了。找到最简单暴力的方法,拷贝。
1.先确定从哪里拷贝什么,很显然我们需要的是A项目bin/(debug|release)目录下的dll文件,有个疑问,这个dll版本会是最新的吗?答:一定是,因为使用MSBuild编译时所有间接引用的项目都会根据指令重新生成。
直接在当前夏木的csproj文件的Project配置节下边添加一个<ItemGroup>配置节,设置我们需要查找的文件。$(Configuration)是指当前编译时使用/p传进来的参数,msbuild会自动替换掉,如使用MSBuild b.csproj /p:Configuration:Release并就会替换成Release。
2.什么时候如何拷贝。这个也很简单。在csproj文件末尾添加Name属性为AfterBuild的Target 配置节。因为这个项目时webApplication项目,所以直接拷贝到bin目录即可。
<Target Name="AfterBuild"> <Copy SourceFiles="@(Dlls)" DestinationFolder="bin\"/> </Target> </Project>
思考:
这个方法方便可靠吗?
肯定不方便,建立每个可执行项目(exe,webApplication)都需要修改一下配置文件。此方法还没有在website上验证。
也不太可靠,如果出现下边的情况会是怎样呢?
这种复制具有不确定性,即大家都不确定最终是哪个版本覆盖哪个版本。实际上这个在我之前写代码的时候就发现了,一直不知道如何处理,两个版本改动不大还好说,如果改动大了呢?我当时的做法是使用Dll Redirection,把低版本重定向高版本。但是这完全是自作自受的做法,在自己可控范围内为什么不用同一个版本的dll呢,如果这样不就可靠了吗?其实有可能还是不可靠,因为还有很多种情况没有检验过,这个方法只限于解决当前问题。常常见到别人和我从同一个出发点开始思考,往往提出了更全面,更前瞻性的解决方案时就觉得很没劲、很自责。想来和经验与性格都有关,有待改进!
不可靠你还拿出来?
完全是记录自己解决问题的思路。其实这种思路并不正确,我总是喜欢做一些模棱两可的事情,表面上看似解决问题了,实际则不然,一直再改进,但起色不大,求指点。
这个是最优方法吗?
不是,如果你打开MSBuild .Targets 文件就发现有很多流程和这个问题相关,很多地方都能解决这个问题,DUDU老大找到一篇资料《resolving binary references in msbuild》就提出了至少2种方法,显示一个简单暴力的方法,接着给出了一个比较perfect的解决方案。
参考:
Copy 任务 http://msdn.microsoft.com/zh-cn/library/3e54c37h(v=VS.100).aspx
MSBuild .Targets 文件http://msdn.microsoft.com/zh-cn/library/ms164312.aspx
ResolveNativeReference 任务 http://msdn.microsoft.com/zh-cn/library/ms164302.aspx
MSbuild http://msdn.microsoft.com/en-us/library/wea2sca5(v=VS.90).aspx