简体   繁体   中英

Command prompt from C# get stuck

I have asked this question the other day, but neither I had an answer nor could I made it work. So I tried to slim it down as it was a lot of noise in the question.

Thing is, if I expose in a web api a all to a method that runs cmd.exe it works fine if I don't call it two times per request.

I mean, this code works fine:

public class FilesController : ApiController
{
    private readonly IRunner _runner;

    public FilesController(IRunner runner)
    {
        _runner = runner;
    }

    public string Get()
    {
        return _runner.GetFiles();
    }
}

public class Runner : IRunner
{
    public Runner()
    {
        //var cd = @"cd C:\DummyFolder";
        //RunCmdPromptCommand(cd);
    }

    public string GetFiles()
    {
        var dir = @"cd C:\DummyFolder & dir";
        //var dir = "dir";
        return RunCmdPromptCommand(dir);
    }

    private string RunCmdPromptCommand(string command)
    {
        var process = new Process
        {
            StartInfo =
            {
                UseShellExecute = false,
                CreateNoWindow = true,
                WindowStyle = ProcessWindowStyle.Hidden,
                RedirectStandardError = true,
                RedirectStandardOutput = true,
                FileName = @"cmd.exe",
                Arguments = string.Format("/C {0}", command)
            }
        };

        process.Start();
        var error = process.StandardError.ReadToEnd();

        if (!string.IsNullOrEmpty(error))
        {
            throw new Exception(error);
        }

        var output = process.StandardOutput.ReadToEnd();

        process.WaitForExit();

        return output;
    }
}

But if I uncomment the lines commented (and obviously comment out the first line of GetFiles , when the code reaches for the second time (ie with "dir") the RunCmdPromptCommand it gets stuck in the line where it tries to read the standard error.

I don't know why, and I don't know how to force the exit whenever it could happen (might be other scenarios that can happen)

Thanks,

This is because the:

process.StandardOutput.ReadToEnd();

Is a synchronous operation.

Excerpt from MSDN :

The redirected StandardError stream can be read synchronously or asynchronously. Methods such as Read, ReadLine, and ReadToEnd perform synchronous read operations on the error output stream of the process. These synchronous read operations do not complete until the associated Process writes to its StandardError stream, or closes the stream .

In other words, as long as the process doesn't write any standard error or closes the stream, it will get stuck there forever.

To fix this, I recommend to use Async BeginErrorReadLine . Excerpt from MSDN:

In contrast, BeginErrorReadLine starts asynchronous read operations on the StandardError stream. This method enables a designated event handler for the stream output and immediately returns to the caller, which can perform other work while the stream output is directed to the event handler .

Which I think will be suitable for your need.

To use that. the example given in the MSDN is pretty straightforward. Check out especially these lines:

 netProcess.ErrorDataReceived += new DataReceivedEventHandler(NetErrorDataHandler); //note this event handler add

if (errorRedirect) //in your case, it is not needed
{
    // Start the asynchronous read of the standard
    // error stream.
    netProcess.BeginErrorReadLine(); //note this
}

And how to define the event handler:

private static void NetErrorDataHandler(object sendingProcess, 
    DataReceivedEventArgs errLine)
{
    // Write the error text to the file if there is something
    // to write and an error file has been specified.

    if (!String.IsNullOrEmpty(errLine.Data))
    {
        if (!errorsWritten)
        {
            if (streamError == null)
            {
                // Open the file.
                try 
                {
                    streamError = new StreamWriter(netErrorFile, true);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Could not open error file!");
                    Console.WriteLine(e.Message.ToString());
                }
            }

            if (streamError != null)
            {
                // Write a header to the file if this is the first
                // call to the error output handler.
                streamError.WriteLine();
                streamError.WriteLine(DateTime.Now.ToString());
                streamError.WriteLine("Net View error output:");
            }
            errorsWritten = true;
        }

        if (streamError != null)
        {
            // Write redirected errors to the file.
            streamError.WriteLine(errLine.Data);
            streamError.Flush();
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM