Is there a better way to call MSBuild from C#/.NET than shelling out to the msbuild.exe? If yes, how?
If all you want is the path to the MSBuild tools folder, you can use the ToolLocationHelper class from the Microsoft.Build.Utilities.Core assembly:
var toolsetVersion = ToolLocationHelper.CurrentToolsVersion;
var msbuildDir = ToolLocationHelper.GetPathToBuildTools(toolsetVersion);
For a .NET 2.0-specific version, you can use the following:
Engine engine = new Engine();
engine.BinPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.System)
+ @"\..\Microsoft.NET\Framework\v2.0.50727";
FileLogger logger = new FileLogger();
logger.Parameters = @"logfile=C:\temp\test.msbuild.log";
engine.RegisterLogger(logger);
string[] tasks = new string[] { "MyTask" };
BuildPropertyGroup props = new BuildPropertyGroup();
props.SetProperty("parm1","hello Build!");
try
{
// Call task MyTask with the parm1 property set
bool success = engine.BuildProjectFile(@"C:\temp\test.msbuild",tasks,props);
}
catch (Exception ex)
{
// your error handler
}
finally
{
engine.UnregisterAllLoggers();
engine.UnloadAllProjects();
}
If you use Microsoft.Build.Engine.Engine
, you'll get a warning: This class has been deprecated. Please use Microsoft.Build.Evaluation.ProjectCollection from the Microsoft.Build assembly instead.
Now, the proper way to run MSBuild from C# looks like this:
public sealed class MsBuildRunner
{
public bool Run(FileInfo msbuildFile, string[] targets = null, IDictionary<string, string> properties = null, LoggerVerbosity loggerVerbosity = LoggerVerbosity.Detailed)
{
if (!msbuildFile.Exists) throw new ArgumentException("msbuildFile does not exist");
if (targets == null)
{
targets = new string[] {};
}
if (properties == null)
{
properties = new Dictionary<string, string>();
}
Console.Out.WriteLine("Running {0} targets: {1} properties: {2}, cwd: {3}",
msbuildFile.FullName,
string.Join(",", targets),
string.Join(",", properties),
Environment.CurrentDirectory);
var project = new Project(msbuildFile.FullName, properties, "4.0");
return project.Build(targets, new ILogger[] { new ConsoleLogger(loggerVerbosity) });
}
}
Yes, add a reference to Microsoft.Build.Engine
and use the Engine class.
PS: Take care to reference the right version. There are 2.0 and 3.5 assemblies and you'll have to make sure that everyone gets the right one.
CurrentToolsVersion is not available in ToolLocationHelper class, I am here using V