ASP.NET gets InvalidOperationException exception on System.Diagnostic.Process object

I have an ASP.NET MVC Framework application in C#. In one of my Controller functions, I get the following errors:
BasePriority = 'process.BasePriority' threw an exception of type 'System.InvalidOperationException'
HandleCount = 'process.HandleCount' threw an exception of type 'System.InvalidOperationException'
MainModule = 'process.MainModule' threw an exception of type 'System.ComponentModel.Win32Exception'
MainWindowHandle = 'process.MainWindowHandle' threw an exception of type 'System.InvalidOperationException'
Modules = 'process.Modules' threw an exception of type 'System.ComponentModel.Win32Exception'
ProcessName = 'process.ProcessName' threw an exception of type 'System.InvalidOperationException'
Position = '((System.IO.FileStream)process.StandardError.BaseStream).Position' threw an exception of type 'System.NotSupportedException'
Threads = 'process.Threads' threw an exception of type 'System.InvalidOperationException'

There are other errors also, Most of them are InvalidOperationException errors.

Here is the code.
[AllowAnonymous]
public ActionResult PrintSummaryPDF()
{
    Process process = null;
    ProcessStartInfo processStartInfo = new ProcessStartInfo();
    processStartInfo.FileName = ConfigurationManager.AppSettings["WkHtmlToPdfExePath"];
    processStartInfo.Verb = "runas";
    processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    processStartInfo.RedirectStandardError = true;
    processStartInfo.RedirectStandardOutput = true;
    processStartInfo.CreateNoWindow = true;
    processStartInfo.UseShellExecute = false;
    string fileNameDatePart = DateTime.Now.ToLongTimeString().Replace(":", string.Empty).Replace(" ", string.Empty);
    string pdfFileName = "Survey" + fileNameDatePart + ".pdf";
    processStartInfo.Arguments = HttpContext.Request.Url.AbsoluteUri.Replace("PrintSummaryPDF", "PrintSummary") + " " +
        " --load-error-handling ignore" + " --cookie .ASPXAUTH " + Request.Cookies["DCCCDCookie"].Value + " \"" + ConfigurationManager.AppSettings["WkHtmlToPdfOutputPath"] + pdfFileName + "\"";
    process = Process.Start(processStartInfo);
    process.WaitForExit(Convert.ToInt32(ConfigurationManager.AppSettings["TimeOut"]));

    int exitCode = process.ExitCode;
    string stdout = process.StandardOutput.ReadToEnd();
    string stderr = process.StandardError.ReadToEnd();

    return File("../pdfoutput/" + pdfFileName, "application/pdf");
}

Open in new window


The browser page then states:
Can’t reach this page
•Make sure the web address http://localhost:54635 is correct

The StandardOutput, stdout, reads:

Qt: Untested Windows version 6.2 detected!
Loading pages (1/6)
[>                                                           ] 0%
[======>                                                     ] 10%
[================>                                           ] 27%
[===================>                                        ] 33%
[=======================>                                    ] 39%
[============================>                               ] 47%
[=====================================>                      ] 62%
[========================================>                   ] 68%
[============================================>               ] 74%
[================================================>           ] 81%
[============================================================] 100%
Counting pages (2/6)                                               
[============================================================] Object 1 of 1
Resolving links (4/6)                                                       
[============================================================] Object 1 of 1
Loading headers and footers (5/6)                                           
Printing pages (6/6)
[>                                                           ] Preparing
[==============================>                             ] Page 1 of 2
[============================================================] Page 2 of 2
Done    

Open in new window


I suspected that the path to, WkHtmlToPdfExePath perhaps did not have sufficient permissions for iisexpress.exe; but when I check the permissions, it has full permissions for my account and the admin account, and I do have admin privileges on this machine.
I also checked the, WkHtmlToPdfOutputPath

This application is running in Visual Studio Enterprise 2017, version 15.8.7

Please advise. Thanks.
Member_2_8198376Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Kelvin McDanielSr. DeveloperCommented:
The problem doesn't appear to be your call to the external process; rather, it appears to be happening during the printing phase of the external process's execution.

Of the Stack Trace you've shared, this appears to be the important part:
ProcessName = 'process.ProcessName' threw an exception of type 'System.InvalidOperationException'
Position = '((System.IO.FileStream)process.StandardError.BaseStream).Position' threw an exception of type 'System.NotSupportedException'

Open in new window


... the exceptions after that are subsequent failures because of this one.

Given the exception I'd wager that the stream being passed into the third-party library is from an HttpWebResponse... because those aren't searchable and as such don't support Position or Length. In the code that calls the library, instead of directly passing the stream from the response, try coping it into a MemoryStream first and pass that to the library. You can read more about the scenario here.
Member_2_8198376Author Commented:
It turns out that the path to the output path was different on the machine of the person who created this app than it was on mine. For that person, the path was as shown in the code above in my question.
I changed it to :
 . . .
 var outputPath = ConfigurationManager.AppSettings["WkHtmlToPdfOutputPath"] + pdfFileName;
 . . .
return File(outputPath, "application/pdf");

Open in new window

And that fixed it.

Kelvin McDaniel,
When you say, library, do you mean the WkHtmlToPdfExePath executable, wkhtmltopdf.exe?
What is the code the calls the library? Is that, Process.Start(processStartInfo);
What code is the stream from the response that you mentioned?
thanks
Kelvin McDanielSr. DeveloperCommented:
That change makes sense. Depending on how wkhtmltopdf.exe works an incorrect path could result in a null Stream, which would of course not have a value for Postion -- hence the error you were seeing.

- The library is whatever wkhtmltopdf.exe itself is using to handle the PDFs. If it's not using a library I'd be very surprised.
- The code that calls the library is wkhtmltopdf.exe.
- The stream is something that wkhtmltopdf.exe would create internally and use to generate the output PDF.
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

Member_2_8198376Author Commented:
Hello Kelvin,
I hope you had a nice weekend. Thank you for your answers. I suspect that if I encounter this again, it will more likely be because of what you said about the memory stream.
Could you provide a code example of what you suggested: "In the code that calls the library, instead of directly passing the stream from the response, try coping it into a MemoryStream first and pass that to the library."
I looked at your link, but I didn't see how to relate it to your suggestion. Thanks.
Kelvin McDanielSr. DeveloperCommented:
Sure. If you run into the problem that I was describing, it would be because whatever is actually making the request to the URL that you're passing in is using a HttpWebRequest. You would then use HttpWebResponse.GetResponseStream() to get the Stream that has the content you requested. Herein lies the "problem".

The fix is relatively simple; once you obtain the handle on the response stream, simply push it into a MemoryStream and use that instead of the response stream itself.

Here's a .NET Fiddle that illustrates what I'm describing.
Member_2_8198376Author Commented:
Hello Kelvin,
   Since my code starts a process, I don't know how to "obtain the handle on the response stream."
   For example, in my code, I start the process like this:
process = Process.Start(processStartInfo);
process.WaitForExit(Convert.ToInt32(ConfigurationManager.AppSettings["TimeOut"]));

Open in new window

Is 'process' the handle on the response stream? In that case, I would do something like,
		process = Process.Start(processStartInfo);
           process.WaitForExit(Convert.ToInt32(ConfigurationManager.AppSettings["TimeOut"]));
		using (process) 
                {
			using(var stream = new MemoryStream()) {
				using(var responseStream = process.GetResponseStream()) {
					responseStream.CopyTo(stream);
				}
				
				// now do whatever you're going to do; in this case, let's tell a little joke...
				stream.Position = 0;
				
				using(var reader = new StreamReader(stream)) {
				   // . . . 
				}				
			}
		}

Open in new window

Is that how I obtain the handle on the response stream?
thanks
Kelvin McDanielSr. DeveloperCommented:
You would need the source code of the wkhtmltopdf.exe to do this.
Member_2_8198376Author Commented:
It turns out that the path to the output path defined in the web.config file was different on the machine of the person who created this app than it was on mine. When I downloaded the code from TFS, it still had the path that worked on the machine of the person who had previously worked on the app.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
ASP.NET

From novice to tech pro — start learning today.