我正在尝试构建一个使用VS2017创建的简单C#7类库项目。
来自框架程序集的MSBuild已过时,因此我在visual studio(Microsoft.Build
)中的MSBuild文件夹中引用了Microsoft.Build.Engine
,Microsoft.Build.Framework
和C:\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".
是否有使用最新构建工具和C#7编译器调用构建的编程方法?
答案 0 :(得分:4)
我的团队有类似的需求,我为C#编写了一个Builder库,支持多个版本的Visual Studio。 我无法使Project.Build功能正常工作,所以我直接执行了MsBuild.exe。
我是如何构建的:
根据Visual Studio版本的项目:
使用包含我需要构建的所有项目的Projects属性
具有与Project
相同的值在注册表中找到:
Registry.LocalMachine.OpenSubKey($@"SOFTWARE\Microsoft\MSBuild\ToolsVersions\{msBuildVersion}")
在注册表中不再需要使用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);
使用自定义XML Logger构建序列化项目 - 您可以使用MsBuildExtensionPack
提供的项目从Xml反序列化结果摘要并使用它来确定构建是否失败,发生了哪些错误和警告等。
答案 1 :(得分:4)
如果您只需要最新MSBuild.exe的路径,请使用Nuget中的 Microsoft.Build.Utilities.Core 并使用以下代码:
ToolLocationHelper.GetPathToBuildToolsFile("msbuild.exe", ToolLocationHelper.CurrentToolsVersion);
无论是安装Build Tools还是完整的Visual Studio安装都可以。
答案 2 :(得分:3)
我的项目中存在完全相同的问题 在我的情况下,我想以编程方式构建一个SSDT项目,但我也尝试了其他项目类型。
有趣的是,它在VS2017的构建版本26228.04(这是Release版本)中工作得非常好,并且在构建版本26228.09中停止工作。
昨天发布的26228.10已经发布,所以我决定再给它一次。
令人惊讶的是,以下内容对我有用:
我从来没有得到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,
// e.g. if you want to just Build the Debug (not Rebuild the Release).
new Dictionary<string, string>
{
{ "Configuration", "Release" },
{ "Platform", "Any CPU" }
}, null, new[] { "Rebuild" }, null));
if (result.OverallResult == BuildResultCode.Failure)
// Something bad happened...
确保已将所有MSBuild装配绑定重定向复制到.config
文件。
如果您还没有这样做,请打开文件C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\15.0\Bin\MSBuild.exe.config
并将整个<runtime>
元素复制到使用MSBuild的项目中您自己的<configuration>
文件的.config
元素编程。
如果您不重定向MSBuild程序集版本,您将从MSBuild获得一些非常奇怪的错误消息,这些消息将根据您的MSBuild版本而有所不同。
但它肯定会说:如果没有装配绑定重定向,它肯定不会起作用。
如果您想构建SSDT项目,还需要执行一个步骤:
从
.sqlproj
文件中的以下两行
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
<VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
到
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
<VisualStudioVersion Condition="'$(SSDTExists)' == ''">15.0</VisualStudioVersion>
我不是百分百肯定为什么,但这些步骤对我来说非常合适! 但是因为MSBuild以编程方式使用有点“难”(在我看来它有时和天气预报一样稳定),所以我的方法可能不适用于你的情况。
答案 3 :(得分:2)
这已在msbuild的PreRelease版本(15.5.0-preview-000072-0942130)中解决,请参阅MsBuild问题#2369: msbuild nuget package unable to open vs2017 csproj files。 因此,将来不需要进一步的黑客攻击
答案 4 :(得分:0)
现在更容易了,因为微软已经发布了他们自己的软件包。
设置包引用 as described here。请注意除 Locator 包之外的所有包上的 ExcludeAssets="runtime"
:
<PackageReference Include="Microsoft.Build.Locator" Version="1.4.1" />
<PackageReference Include="Microsoft.Build" Version="16.10.0" ExcludeAssets="runtime" />
<PackageReference Include="Microsoft.Build.Utilities.Core" Version="16.10.0" ExcludeAssets="runtime" />
public Init()
{
MSBuildLocator.RegisterDefaults();
var project = LoadProject(@"C:\Path\To\Project.csproj");
}
public Project LoadProject(string csprojPath)
{
var context = new ProjectCollection();
return context.LoadProject(csprojPath);
}
根据上面的文档链接,对 Microsoft.Build 程序集的调用需要以与 MSBuildLocator.RegisterDefaults()
不同的方法发生。