1

I just asked for the Input and now I have to ask for the Output. This already worked, but apparently I changed something important.

I want to read the Output of an SqlPlus Process. The reading itself works, but then it exits further Execution. I am using DI, but it doesn´t work within a single class either.

Program.cs:

builder.Services.AddScoped<IExecuter,ShellExecuter>();

ShellExecuter.cs:

 private List<string> _commands = new List<string>();
   private Process _process;
    private ProcessStartInfo _startInfo;
   


public ShellExecuter(){
           _startInfo = new ProcessStartInfo();
            _startInfo.WorkingDirectory = Path.GetTempPath();
            _startInfo.FileName = "sqlplus.exe";
            _startInfo.UseShellExecute = false;
            _startInfo.RedirectStandardOutput = true;
            _startInfo.RedirectStandardError = true;
            _startInfo.RedirectStandardInput = true;
            _startInfo.CreateNoWindow = true;
            _process = new Process();
        }


 public void Start()
                {
                    _startInfo.Arguments = $"-s user/pass@db";
                    _process.StartInfo = _startInfo;    
                   // _process.EnableRaisingEvents = true;
                    _process.Start();
         _process.ErrorDataReceived += (sender, args) =>
        {
            System.Diagnostics.Debug.WriteLine("Error:  " + args.Data);
        };           
        process.Exited += new System.EventHandler(Exited);

            }

 ...Methods to add to _commands and Write them.

 public string Output()
        {         
            string line = "";
            while (!_process.StandardOutput.EndOfStream)
            {
                line += _process.StandardOutput.ReadLine();
                System.Diagnostics.Debug.WriteLine("Output: " + line);
            }
      }

HomeController.cs:

 public IActionResult Index(IExecuter exec)
        {
            exec.Start();    
            exec.AddCommand(" create or replace view testview(ID) as select ID from 
     MyUSER;");   
            exec.Execute();  
            var output = exec.Output();

            return Content(output);
        }

So, when I run this it properly creates the View and goes into the Output loop. However, after I get the "Output: View created.", it will take ~1s and then I will get the message "The Thread xxxxx has exited with Code 0" I am not sure if this exit is about the Process or the ShellExecuter, but I don´t get out of the While Loop anymore and the Debugger does not show the Buttons to jump to the next Line anymore. Nor does the Website update.

What do I overlook here? It already worked...

SuperNev
  • 31
  • 5
  • The exited event occurred. S you need to handle the exit and then when exit event occurs allow to break out of while loop. Tyr using a WaitHandle to break out of while loop. Set wait handle in the exit event. See : https://learn.microsoft.com/en-us/dotnet/api/system.threading.waithandle.waitone?force_isolation=true&view=net-6.0 – jdweng Aug 10 '22 at 14:19

1 Answers1

0

In order to read the output you need to attach to the event like this

_process.OutputDataReceived += new DataReceivedEventHandler(DataReceived);

with a method like this

public StringBuilder Output = new StringBuilder();
void DataReceived(object sender, DataReceivedEventArgs e)
{
    Output.AppendLine(e.Data);
}

then also add this

_process.Start();
_process.WaitForExit(); //very important!

then you can call

var output = exec.Output.ToString();
Bron Davies
  • 5,930
  • 3
  • 30
  • 41
  • Ahhh, I wanted it to be Synchronosly and therefore did not use the Events. But you use WaitForExit and basically make it synchron. No? – SuperNev Aug 11 '22 at 06:42
  • Is there anything else I have to add? When I do this I just get the same behaviour. The Event will be called with the "View created" and after that not do anything anymore and wait indefinitely. – SuperNev Aug 11 '22 at 07:17
  • try removing the code for `_startInfo.CreateNoWindow = true;` and `process.Exited += new System.EventHandler(Exited);` sqlplus is intended for interactive execution which means it could hang at any point if it has to prompt for something. If you can change your implementation to use something that doesn't rely on this, you'll be better off. See https://stackoverflow.com/questions/638705/how-can-i-issue-a-single-command-from-the-command-line-through-sql-plus – Bron Davies Aug 11 '22 at 14:48