ejecutando msbuild programáticamente

Estoy intentando ejecutar msbuild de forma programática y no puedo ejecutar el siguiente comando:

string command = string.Format(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe ""{0}\{1}.csproj""", _args.ProjectPath, _args.ProjectName); 

la cadena se representa como:

 C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "C:\...\TestResults\Foo 2011-08-31 16_29_40\Out\Foo\solutionName\projectName\projectName.csproj" 

Luego uso el nuevo ProcessStartInfo (comando). El problema parece ser el espacio entre Foo y 2011. Obtengo el siguiente resultado:

 MSBUILD : error MSB1008: Only one project can be specified. Switch: 16_29_40\Out\Foo\solutionName\projectName\projectName.csproj 

¿Cómo paso el archivo de proyecto a msbuild?

Recomendaría stronlgy para ir a la ruta oficial a través de clases / interfaces en Microsoft.Build espacio de nombres Microsoft.Build . Microsoft usa esto por todos lados, así que esto debería contar para algo …

Esp. la clase Microsoft.Build.Execution.BuildManager y Singleton Microsoft.Build.Execution.BuildManager.DefaultBuildManager es lo que está buscando para ejecutar una tarea de comstackción … ejemplos del código fuente:

Debe usar la propiedad Arguments de ProcessStartInfo para pasar los parámetros.

p.ej

 var p = new Process(); p.StartInfo = new ProcessStartInfo(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe") p.StartInfo.Arguments = string.Format(@"{0}\{1}.csproj", _args.ProjectPath, _args.ProjectName) p.Start(); 

Sin embargo, para MSBuild específicamente debes usar el método oficial como menciona Yahia .

Aquí un ejemplo completo de trabajo con un registrador simple.

Para construir una solución:

  using Microsoft.Build.Evaluation; using Microsoft.Build.Execution; string projectFileName = "C:\\Users...\\MySolution.sln";//<--- change here can be another VS type ex: .vcxproj BasicLogger Logger = new BasicLogger(); var projectCollection = new ProjectCollection(); var buildParamters = new BuildParameters(projectCollection); buildParamters.Loggers = new List() { Logger }; var globalProperty = new Dictionary(); globalProperty.Add("Configuration", "Debug"); //<--- change here globalProperty.Add("Platform", "x64");//<--- change here BuildManager.DefaultBuildManager.ResetCaches(); var buildRequest = new BuildRequestData(projectFileName, globalProperty, null, new String[] { "Build" }, null); var buildResult = BuildManager.DefaultBuildManager.Build(buildParamters, buildRequest); if (buildResult.OverallResult == BuildResultCode.Failure) { // catch result .. } MessageBox.Show(Logger.GetLogString()); //display output .. 

y la clase logger (fuertemente derivada de este registrador msdn):

  public class BasicLogger : Logger { MemoryStream streamMem = new MemoryStream(); ///  /// Initialize is guaranteed to be called by MSBuild at the start of the build /// before any events are raised. ///  public override void Initialize(IEventSource eventSource) { try { // Open the file this.streamWriter = new StreamWriter(streamMem); //this.streamWriter = new StreamWriter(logFile); } catch (Exception ex) { if ( ex is UnauthorizedAccessException || ex is ArgumentNullException || ex is PathTooLongException || ex is DirectoryNotFoundException || ex is NotSupportedException || ex is ArgumentException || ex is SecurityException || ex is IOException ) { throw new LoggerException("Failed to create log file: " + ex.Message); } else { // Unexpected failure throw; } } // For brevity, we'll only register for certain event types. Loggers can also // register to handle TargetStarted/Finished and other events. eventSource.ProjectStarted += new ProjectStartedEventHandler(eventSource_ProjectStarted); eventSource.TaskStarted += new TaskStartedEventHandler(eventSource_TaskStarted); eventSource.MessageRaised += new BuildMessageEventHandler(eventSource_MessageRaised); eventSource.WarningRaised += new BuildWarningEventHandler(eventSource_WarningRaised); eventSource.ErrorRaised += new BuildErrorEventHandler(eventSource_ErrorRaised); eventSource.ProjectFinished += new ProjectFinishedEventHandler(eventSource_ProjectFinished); } void eventSource_ErrorRaised(object sender, BuildErrorEventArgs e) { // BuildErrorEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters string line = String.Format(": ERROR {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber); WriteLineWithSenderAndMessage(line, e); } void eventSource_WarningRaised(object sender, BuildWarningEventArgs e) { // BuildWarningEventArgs adds LineNumber, ColumnNumber, File, amongst other parameters string line = String.Format(": Warning {0}({1},{2}): ", e.File, e.LineNumber, e.ColumnNumber); WriteLineWithSenderAndMessage(line, e); } void eventSource_MessageRaised(object sender, BuildMessageEventArgs e) { // BuildMessageEventArgs adds Importance to BuildEventArgs // Let's take account of the verbosity setting we've been passed in deciding whether to log the message if ((e.Importance == MessageImportance.High && IsVerbosityAtLeast(LoggerVerbosity.Minimal)) || (e.Importance == MessageImportance.Normal && IsVerbosityAtLeast(LoggerVerbosity.Normal)) || (e.Importance == MessageImportance.Low && IsVerbosityAtLeast(LoggerVerbosity.Detailed)) ) { WriteLineWithSenderAndMessage(String.Empty, e); } } void eventSource_TaskStarted(object sender, TaskStartedEventArgs e) { // TaskStartedEventArgs adds ProjectFile, TaskFile, TaskName // To keep this log clean, this logger will ignore these events. } void eventSource_ProjectStarted(object sender, ProjectStartedEventArgs e) { // ProjectStartedEventArgs adds ProjectFile, TargetNames // Just the regular message string is good enough here, so just display that. WriteLine(String.Empty, e); indent++; } void eventSource_ProjectFinished(object sender, ProjectFinishedEventArgs e) { // The regular message string is good enough here too. indent--; WriteLine(String.Empty, e); } ///  /// Write a line to the log, adding the SenderName and Message /// (these parameters are on all MSBuild event argument objects) ///  private void WriteLineWithSenderAndMessage(string line, BuildEventArgs e) { if (0 == String.Compare(e.SenderName, "MSBuild", true /*ignore case*/)) { // Well, if the sender name is MSBuild, let's leave it out for prettiness WriteLine(line, e); } else { WriteLine(e.SenderName + ": " + line, e); } } ///  /// Just write a line to the log ///  private void WriteLine(string line, BuildEventArgs e) { for (int i = indent; i > 0; i--) { streamWriter.Write("\t"); } streamWriter.WriteLine(line + e.Message); } public string GetLogString() { var sr = new StreamReader(streamMem); var myStr = sr.ReadToEnd(); return myStr; } ///  /// Shutdown() is guaranteed to be called by MSBuild at the end of the build, after all /// events have been raised. ///  /// /// public override void Shutdown() { streamWriter.Flush(); streamMem.Position = 0; } private StreamWriter streamWriter; private int indent; } 

También asegúrese de usar los ensamblajes de Framework de MSBuild correctos (es decir, no la versión "4.0") (vea aquí )