After a few days of research, I think I came across an answer - which I decided to share here, since I'm not the only one who run into this. Maybe my efforts, will be useful to somebody. At first, I'll post a short answer and afterwards, I'll post my research and explanations. Since I do not consider myself to be C# or Dot Net Guru, I'll more than glad for community collaboration on this, correcting and improving this answer. That way we get StackOverfllow better for everyone, no? :)
Short Answer:
There's nothing you can you about it. Such deadlocks seems to be inherent in the way synchronous reads are implemented (I'm using .Net 4.0 Framework), hence if you can - avoid running into troubles in the first place and prefer asynchronous reads. Since your code may ran on your PC (=development environment) but fail deployed to IIS, as it did exactly with me. Probably the only workaround you can use, is when your expected output (= you sure (!) there is an output, waiting to be red) ends with definitive pattern, which you can recognize and stop reading.
Long Answer:
The issue seams to arise when you're trying to read from standard output, when there's nothing waiting for you there.
This can arise when (a) there's no output in the first place or, (b) you just finished reading what have been there and "advanced to the next" (non-existing) character or string. While (b) being more dangerous IMHO, since it's easy not to read when you expect no output, but much harder to stop, when there are no conditions for you to know when (at least, I was unable to find such by debugging my code and documented in MSDN - the silence on my question is another evidence for the same).
On first glance, you can use Peek() method, which promises "Returns the next available character but does not consume it" and you can easily find across the web examples, when using Peek() seems to do the trick. Unfortunately, MSDN also says "or -1 if there are no characters to be read or if the stream does not support seeking". Well guess what, at least in my case - standard output does not support seeking. Hence Peek() was rather unusable. It did worked a couple of time (maybe someone with deeper understanding can explain why), but I suspect I didn't got the whole output in such cases.
Now, I'd like to iterate the methods I've used and their outcome, so you can learn from my research and know what to expect from your code:
- StreamReader.Read() within While(!StreamReader.EndOfStream) - Hangs
at execution.
- StreamReader.Read() within While(StreamReader.Peek() > -1) - Skips the loop.
- StreamReader.ReadLine() - Hangs at execution.
- StreamReader.ReadToEnd() - Hangs at execution.
- StreamReader.BaseStream.Length - Exception at runtime: Stream does not support seeking
- StreamReader.Read() / StreamReader.BaseStream.ReadByte() - A special case, upon which I got to my conclusion - both read fine, till reading exactly the next character after current buffer ends. Than hangs.
It's seems to me that current implementation or Process.StandardOutput lacks any method of recognizing when we red all there is. That's why in my humble opinion, all methods besides Read() and ReadByte() hangs. And those two will hang also, if you stepped across the current stream edge. In my case, I was able to move to SSH.Net (which I'd like to thank the contributors of that wonderful project). By the way, it never hangs at sshReader.ReadToEnd() :)
PPS: My development environment for those of you wondering: VisualStudio 2010 Ultimate on Windows 7 64bit and IIS 8 (clean install) with Framework 4.