以编程方式构建msbuild 15项目

我正在尝试构建一个使用VS2017创建的简单C#7类库项目。

框架程序集中的MSBuild已过时,因此我在C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin MSBuild文件夹中引用Microsoft.BuildMicrosoft.Build.EngineMicrosoft.Build.FrameworkC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin )。

当我这样做时:

 using (var collection = new ProjectCollection()) { var proj = collection.LoadProject(@"c:\projects\Sample\Sample.csproj"); // <-- exception proj.Build(new[] {new ConsoleLogger()}); } 

我收到了InvalidProjectFileException: The tools version "15.0" is unrecognized. Available tools versions are "4.0", "2.0". InvalidProjectFileException: The tools version "15.0" is unrecognized. Available tools versions are "4.0", "2.0".

是否有使用最新构建工具和C#7编译器调用构建的编程方法?

我对我的团队有类似的需求,我为C#编写了一个Builder库,支持多个版本的Visual Studio。 我无法使Project.Buildfunction正常工作,所以我直接执行了MsBuild.exe。

我是如何建造它的:

使用NuGet的 Microsoft.Build.Framework

使用名为Build的1个目标创建一个新的Project对象

定义正确的ToolsVersion

根据Visual Studio版本的项目:

  • 2010年,2012年=> 4.0
  • 2013 => 12.0
  • 2015 => 14.0
  • 2017 => 15.0

添加MsBuild类型的新任务

使用Projects属性包含我需要构建的所有项目

定义ToolsVersion

MsBuild任务的值与项目的值相同

将项目序列化为临时文件

根据ToolsVersion找到正确的MsBuild.exe

4.0,12.0,14.0

在注册表中找到:

 Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\{msBuildVersion}") 

15.0

在注册表中不再需要使用Nuget包Microsoft.VisualStudio.Setup.Configuration.Interop

  var query = new SetupConfiguration(); var query2 = (ISetupConfiguration2)query; var e = query2.EnumAllInstances(); var helper = (ISetupHelper)query; int fetched; var instances = new ISetupInstance[1]; do { e.Next(1, instances, out fetched); if (fetched > 0) { var instance = instances[0]; var instance2 = (ISetupInstance2)instance; var state = instance2.GetState(); // Skip non-complete instance, I guess? // Skip non-local instance, I guess? // Skip unregistered products? if (state != InstanceState.Complete || (state & InstanceState.Local) != InstanceState.Local || (state & InstanceState.Registered) != InstanceState.Registered) { continue; } var msBuildComponent = instance2.GetPackages() .FirstOrDefault( p => p.GetId() .Equals("Microsoft.Component.MSBuild", StringComparison.InvariantCultureIgnoreCase)); if (msBuildComponent == null) { continue; } var instanceRootDirectory = instance2.GetInstallationPath(); var msbuildPathInInstance = Path.Combine(instanceRootDirectory, "MSBuild", msBuildVersion, "Bin", "msbuild.exe"); if (File.Exists(msbuildPathInInstance)) { return msbuildPathInInstance; } } } while (fetched > 0); 

执行MsBuild.exe

使用自定义XML Logger构建序列化项目 – 您可以使用MsBuildExtensionPack提供的项目

阅读结果摘要

从Xml反序列化结果摘要并使用它来确定构建是否失败,发生了哪些错误和警告等。

如果您只需要最新MSBuild.exe的路径,请使用Nuget的Microsoft.Build.Utilities.Core并使用以下代码:

 ToolLocationHelper.GetPathToBuildToolsFile("msbuild.exe", ToolLocationHelper.CurrentToolsVersion); 

无论是安装Build Tools还是完整的Visual Studio安装,这都有效。

我在项目中遇到了完全相同的问题。
在我的情况下,我想以编程方式构建一个SSDT项目,但我也尝试了其他项目类型。

有趣的是,它在VS2017的构建26228.04(这是Release版本)中运行得非常好,并且在构建版本26228.09中停止工作。
昨天发布的26228.10已经发布,所以我决定再给它一次。

令人惊讶的是,以下对我有用:

  1. 使用Visual Studio Installer更新到最新的VS2017版本26228.10。
  2. 我从来没有能够获得collection.LoadProject(...)工作而不会得到一些奇怪的错误,但你可以使用此代码来进行构建:

     BuildResult result = null; using (var pc = new ProjectCollection()) result = BuildManager.DefaultBuildManager.Build( new BuildParameters(pc) { Loggers = new[] { new ConsoleLogger() } }, // Change this path to your .sln file instead of the .csproj. // (It won't work with the .csproj.) new BuildRequestData(@"c:\projects\Sample.sln", // Change the parameters as you need them, // eg if you want to just Build the Debug (not Rebuild the Release). new Dictionary { { "Configuration", "Release" }, { "Platform", "Any CPU" } }, null, new[] { "Rebuild" }, null)); if (result.OverallResult == BuildResultCode.Failure) // Something bad happened... 
  3. 确保已将所有MSBuild程序集绑定重定向复制到.config文件。
    如果您还没有这样做,请打开文件C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe.config并将整个元素复制到以编程方式使用MSBuild的项目中您自己的.config文件的元素。
    如果您不重定向MSBuild程序集版本,您将从MSBuild获得一些非常奇怪的错误消息,这些消息将根据您的MSBuild版本而有所不同。
    但它肯定会说:如果没有assembly绑定重定向,它绝对不会起作用。

  4. 如果要构建SSDT项目,还需要执行一个步骤:
    更改.sqlproj文件中的以下两行

     11.0 11.0 

     15.0 15.0 

我不是100%肯定为什么,但这些步骤对我来说非常合适!
但是因为MSBuild在编程上有点“难”(在我看来它有时和天气预报一样稳定),所以我的方法很可能不适用于你的情况。

这已在msbuild的PreRelease版本( 15.5.0-preview-000072-0942130 )中解决,请参阅MsBuild问题#2369:msbuild nuget包无法打开vs2017 csproj文件 。 因此,将来不再需要进一步的黑客攻击