C#: Execute process and read both standard output and standard error output


In order to execute external process and read the redirected standard output and standard error output you need make sure that it is thread safe.


Introduction

System.Diagnostics.Process class can be used to execute any external process and writes the text on to the console.

In order to read this text output and manipulate it in the code without getting any Invalid Operation Exception, we need to redirect the standard stream output by setting the property ProcessStartInfo.RedirectStandardOutput to true and ProcessStartInfo.UseShellExecute to false.

The redirected StandardOutput and StandardError streams can be read synchronously using Read, ReadLine or ReadToEnd methods and asynchronously by attaching an event handler for OutputDataReceived event and by calling BeginOutputReadLine or BeginErrorReadLine method.

Reading both StandardError and StandardOutput both synchronously/asynchronously will result in deadlock. Hence we need to read one synchronously and other asynchronously.

Here is the best way to capture both standard output and standard error information by executing the Process.

   

 
/// <summary>
/// Executes the command.
/// </summary>
/// <param name="arguments">The arguments.
/// <param name="workingDir">The working dir.
/// <returns></returns>
private string ExecuteCommand(string arguments, string workingDir)
{
  string errorMessage = string.Empty;
  output = new StringBuilder();
  using (Process prsProjectTypes = new Process())
  {
     prsProjectTypes.EnableRaisingEvents = false;
     prsProjectTypes.StartInfo.UseShellExecute = false;
     prsProjectTypes.StartInfo.RedirectStandardOutput = true;
     prsProjectTypes.StartInfo.RedirectStandardError = true;
     prsProjectTypes.StartInfo.CreateNoWindow = true;
     prsProjectTypes.StartInfo.FileName = mkssiPath;
     prsProjectTypes.StartInfo.Arguments = arguments;
     if (!string.IsNullOrEmpty(workingDir))
     {
        prsProjectTypes.StartInfo.WorkingDirectory = workingDir;                
    }
     prsProjectTypes.Start();

     // Handle Standard Output
     prsProjectTypes.OutputDataReceived = new DataReceivedEventHandler(prsProjectTypes_OutputDataReceived);
     prsProjectTypes.BeginOutputReadLine();
 
     // Handle Error Output
     errorMessage = prsProjectTypes.StandardError.ReadToEnd();
     prsProjectTypes.WaitForExit();
    if (prsProjectTypes.ExitCode != 0)
    {
       errorMessage = "Exit Code: " prsProjectTypes.ExitCode "\r\n" errorMessage;
    }
    else
    {
        errorMessage = string.Empty;
     }
     prsProjectTypes.Close();
     prsProjectTypes.Dispose();
  }
  
 if (!string.IsNullOrEmpty(errorMessage))
  {
    // TO DO: Log Error
  }

  return this.output.ToString().TrimEnd();
}

/// <summary>
/// Standard Output from process
/// </summary>
private StringBuilder output = new StringBuilder();

/// <summary>
/// Handles the OutputDataReceived event of the prsProjectTypes control.
/// </summary>
/// <param name="sender">The source of the event.
/// <param name="e">The <see cref="System.Diagnostics.DataReceivedEventArgs"> instance containing the event data.
private void prsProjectTypes_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
  output.AppendLine(e.Data);
}




Related tags

System.Diagnostics.Process, StandardError, StandardOutput