Avatar of Member_2_8198376
Member_2_8198376

asked on 

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.
ASP.NETC#Microsoft Visual Studio

Avatar of undefined
Last Comment
Member_2_8198376
Avatar of Kelvin McDaniel
Kelvin McDaniel
Flag of United States of America image

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.
Avatar of Member_2_8198376
Member_2_8198376

ASKER

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
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.
Avatar of Member_2_8198376

ASKER

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.
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.
Avatar of Member_2_8198376

ASKER

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
You would need the source code of the wkhtmltopdf.exe to do this.
ASKER CERTIFIED SOLUTION
Avatar of Member_2_8198376
Member_2_8198376

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
ASP.NET
ASP.NET

The successor to Active Server Pages, ASP.NET websites utilize the .NET framework to produce dynamic, data and content-driven web applications and services. ASP.NET code can be written using any .NET supported language. As of 2009, ASP.NET can also apply the Model-View-Controller (MVC) pattern to web applications

128K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo