c# msbuild processstartinfo

c# - ejecutando msbuild programáticamente



processstartinfo (3)

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

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<Microsoft.Build.Framework.ILogger>() { Logger }; var globalProperty = new Dictionary<String, String>(); 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 del registrador (derivada fuertemente de este logger msdn):

public class BasicLogger : Logger { MemoryStream streamMem = new MemoryStream(); /// <summary> /// Initialize is guaranteed to be called by MSBuild at the start of the build /// before any events are raised. /// </summary> 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); } /// <summary> /// Write a line to the log, adding the SenderName and Message /// (these parameters are on all MSBuild event argument objects) /// </summary> 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); } } /// <summary> /// Just write a line to the log /// </summary> 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; } /// <summary> /// Shutdown() is guaranteed to be called by MSBuild at the end of the build, after all /// events have been raised. /// </summary> /// /// public override void Shutdown() { streamWriter.Flush(); streamMem.Position = 0; } private StreamWriter streamWriter; private int indent; }

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

Estoy intentando ejecutar msbuild de manera 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"

Entonces 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 del proyecto a msbuild?


Debe usar la propiedad Arguments de ProcessStartInfo para pasar 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 lo menciona Yahia .


Recomendaría la opción de ir a la ruta oficial a través de las clases / interfaces en Microsoft.Build espacio de nombres de Microsoft.Build . Microsoft usa esto por todas partes, así que esto debería contar para algo ...

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