26

Is there a better way to call MSBuild from C#/.NET than shelling out to the msbuild.exe? If yes, how?

1

5 Answers 5

28

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.

Sign up to request clarification or add additional context in comments.

Comments

16

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();
}

Comments

1

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) });
    }

}

Comments

1

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);

2 Comments

CurrentToolsVersion is not available in ToolLocationHelper class
@nainaigu: Make sure you're using the ToolLocationHelper from Microsoft.Build.Utilities.Core and not the one from Microsoft.Build.Utilities.
0

CurrentToolsVersion is not available in ToolLocationHelper class, I am here using V

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.