Build on TFS 2013 failed but okay locally

2019-01-11 06:07发布

问题:

When I checked in the code, TFS 2013 built the solution automatically. It is okay in local VS 2013 but failed in TFS.

Here is the summary.

Summary
FTPProcessor | Any CPU
1 error(s), 56 warning(s) 
$/xxxx/NewServiceHost/New-Branch/NewServiceHost/packageRestore.proj - 0 error(s), 0 warning(s) 
$/xxxx/NewServiceHost/New-Branch/GenericWindowsServices.sln - 1 error(s), 56 warning(s) 
C:\Builds\1\xxxx\FTP Processor (New)\src\.nuget\nuget.targets (71): The task factory "CodeTaskFactory" could not be loaded from the assembly "C:\Program Files (x86)\MSBuild\12.0\bin\amd64\Microsoft.Build.Tasks.v4.0.dll". Could not load file or assembly 'file:///C:\Program Files (x86)\MSBuild\12.0\bin\amd64\Microsoft.Build.Tasks.v4.0.dll' or one of its dependencies. The system cannot find the file specified.
Other Errors 
1 error(s) 
Exception Message: MSBuild error 1 has ended this build. You can find more specific information about the cause of this error in above messages. (type BuildProcessTerminateException) Exception Stack Trace: at System.Activities.Statements.Throw.Execute(CodeActivityContext context) at System.Activities.CodeActivity.InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager) at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)

回答1:

Your TFS 2013 build server is using MSBuild 12.0 where CodeTasksFactory exists in Microsoft.Build.Tasks.v12.0.dll rather than Microsoft.Build.Tasks.v4.0.dll.

Ideally you should be doing the following:

1) Open your NuGet.targets file: C:\Builds\1\xxxx\FTP Processor (New)\src.nuget\nuget.targets

2) Identify the task referencing the old DLL.

<UsingTask AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll" TaskFactory="CodeTaskFactory" >
...

3) Then future proof it like so:

<UsingTask AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v$(MSBuildToolsVersion).dll" TaskFactory="CodeTaskFactory" >
...


回答2:

As of VS2013, you should be running MSBuild from C:\Program Files (x86)\MSBuild\12.0\Bin\

not from C:\Windows\Microsoft.NET\Framework64\v4.0.30319. See

http://blogs.msdn.com/b/visualstudio/archive/2013/07/24/msbuild-is-now-part-of-visual-studio.aspx

source:http://gyorgybalassy.wordpress.com/2013/12/31/msb4175-the-task-factory-codetaskfactory-could-not-be-loaded/

it solved the issue for me.



回答3:

After much research and trying a bunch of "hacks" I went on to understand the exact mechanics of nuget restore. It turns out, everything has changed since nuget 2.7+ and you're no longer required to include ".nuget" folder and the associated nuget.exe and nuget.target

To fix my build process and use the latest recommended approach, I did the following:

  • Move nuget.config to be with .sln file same folder path
  • Delete ".nuget" folder entirely
  • Delete references to that folder in .sln file
  • Delete following lines from any .csproj file

--

<RestorePackages>true</RestorePackages>
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />

--

This could take some time if your project solution has many files or you work on many projects built with Visual Studio 2013 and before.

The good news is, there's a powershell script that applies the above recursively on any folder:

  • https://github.com/owen2/AutomaticPackageRestoreMigrationScript/blob/master/migrateToAutomaticPackageRestore.ps1

In short, it reverses "Enable Nuget Package Restore", allowing the newer package restore method to work.

In Visual Studio 2013, automatic package restore became part of the IDE (and the TFS build process). This method is more reliable than the older, msbuild integrated package restore. It does not require you to have nuget.exe checked in to each solution and does not require any additional msbuild targets. However, if you have the files related to the old package restore method in your project, Visual Studio will skip automatic package restore. (This behavior is likely to change soon, hopefully it does).

You can use this script to remove nuget.exe, nuget.targets, and all project and solution references to nuget.targets so you can take advantage of Automatic Package Restore. It more or less automates the process described here.

It will recurse through the directory you run the script from and do it to any solutions that may be in there somewhere. Be careful and have fun! (not responsible for anything that breaks)

A couple of good links on the subject:

  • http://blog.davidebbo.com/2014/01/the-right-way-to-restore-nuget-packages.html
  • http://docs.nuget.org/consume/package-restore/migrating-to-automatic-package-restore


回答4:

I had a similar issue. We are forced into using the older msbuild that comes with the framework, rather than the v14 version that comes with visual studio 2015 because we build some old Delphi.net code. Our vcxproj files are triggering some automatic code analysis target which has a task that relies on Microsoft.Build.Tasks.v12.0.dll. I was able to override that task by copying and pasting it into the top of the vcxproj and tweaking the path to the dll. The original task can be found in "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\CodeAnalysis\Microsoft.CodeAnalysis.Targets". So, in other words, you might be able to override the problem task in your project.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <!-- override a task which we can't use with the old msbuild -->
  <UsingTask TaskName="SetEnvironmentVariable" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
    <ParameterGroup>
      <EnvKey ParameterType="System.String" Required="true" />
      <EnvValue ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Using Namespace="System" />
      <Code Type="Fragment" Language="cs">
        <![CDATA[
            try {
                Environment.SetEnvironmentVariable(EnvKey, EnvValue, System.EnvironmentVariableTarget.Process);
            }
            catch  {
            }
        ]]>
      </Code>
    </Task>
  </UsingTask>