Why Process.Start doesn't work from asp.net web service? - c#

Why this code runs perfectly on my development computer (win7 32bit) and on target server(2008r2 64bit) as console app. But when I try to run it as a web service on the target server it does nothing. No error, nothing.
If I remove
exitMsg = proc.StandardOutput.ReadToEnd();
then it fail with error:
System.InvalidOperationException:
Process must exit before requested
information can be determined.
[WebMethod]
public string GetRunningProcesses()
{
ProcessStartInfo pInfo = new ProcessStartInfo();
pInfo.FileName = #"E:\bin\PsList.exe";
pInfo.WindowStyle = ProcessWindowStyle.Hidden;
pInfo.CreateNoWindow = true;
pInfo.UseShellExecute = false;
pInfo.RedirectStandardOutput = true;
string exitMsg = "";
int exitCode = 1;
using (Process proc = Process.Start(pInfo))
{
exitMsg = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(1000);
exitCode = proc.ExitCode;
}
return exitMsg;
}
I think there must be something about user under which code runs. As web service this code runs under asp.net user and this might couses the problems.
Please advice me how to fix this. Thank you very much.
RESOLVED
The problem was with EULA dialog, which poped up but it was invisble due to ProcessStartInfo settings.
When I run PsList.exe via CMD under account which is also used for Application pool for this web service, I get prompted for an EULA agreement and after that everthing works fine.
The strange thing is that I have "pInfo.Arguments = "/accepteula";" in my real code. This should prevent my probem, but it didn't and I don't know why.
If any of you knows why, please tell me.
Thank you very much for all the help. You are trully good peoples here.

I think your only problem is with:
proc.WaitForExit(1000);
Which instructs the program to wait for a second for the process to finish. On your machine, the process finishes fine. On another machine, though, it may take longer. Try changing to:
proc.WaitForExit();
Which will wait indefinitely for the program to exit.
You may also want to redirect the output of the Process to see if the programming is hanging or waiting for something else from you (or, in this case, your code).
In addition, the process may be hitting an error and writing a message to StandardError rather than StandardOutput. Try setting pInfo.RedirectStandardError = true; and reading that as well to see if there's anything you're missing.

The problem was with EULA dialog, which poped up but it was invisble due to ProcessStartInfo settings.
When I run PsList.exe via CMD under account which is also used for Application pool for this web service, I get prompted for an EULA agreement and after that everthing works fine.
The strange thing is that I have "pInfo.Arguments = "/accepteula";" in my real code. This should prevent my probem, but it didn't and I don't know why.
If any of you knows why, please tell me.
Thank you very much for all the help. You are trully good peoples here.

Try wrapping your business logic in a try / catch block that catches any exception and either writes it to the output or to a log file.

Related

Elimininating Process.WaitForExit() / StandardOutput deadlock condition

I've read about this deadlock condition that I'm pretty certain is affecting my code (below). What I don't understand is: this code worked perfectly well running on Windows Server 2003 (.net 2.0) for the past 12 years. Now we've been trying to move it to Windows Server 2012, where it always deadlocks.
While my DLLs are built for "anyCPU" (still targeting .net 2.0), the executable process being run is absolutely 32-bit, and the move from Server 2003 to Server 2012 goes from a 32-bit to 64-bit OS.
I think I understand what to do to resolve the issue, but does anyone know why this behavior would have changed from Server 2003 to Server 2012?
public string DoMyProcess(string filenameAndPath, string arguments)
{
string stdout="";
int exitCode = 0;
try
{
ProcessStartInfo procStartInfo = new ProcessStartInfo();
procStartInfo.FileName = filenameAndPath;
procStartInfo.CreateNoWindow = true;
procStartInfo.Arguments = arguments;
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
System.Diagnostics.Process theProcess = null;
try
{
theProcess = Process.Start(procStartInfo);
theProcess.WaitForExit();
exitCode = theProcess.ExitCode;
// moving this ABOVE WaitForExit should eliminate deadlocks
// But why did it always work on Server 2003 but not on Server 2012?
stdout = theProcess.StandardOutput.ReadToEnd();
}
catch (System.Exception e)
{
string errMsg = e.Message;
log_the_error("threw an exception: " + e.Message);
}
}
return stdout;
}
UPDATE:
Mystery deadlock still exists, even after changing the above code as recommended:
try
{
theProcess = Process.Start(procStartInfo);
stdout = theProcess.StandardOutput.ReadToEnd();
}
catch (System.Exception e)
{
string errMsg = e.Message;
log_the_error("threw an exception: " + e.Message);
}
}
What other conditions could cause that deadlock? If I were to examine StandardError, would it reveal anything useful?
UPDATE #2:
FWIW, we have provisioned another Windows Server 2003 (32-bit), which runs IIS 6. That was the original machine configuration this code ran on for 12 years (with only an occasional deadlock). Our same code that deadlocks on Server 2012 IIS 8 DOES NOT DEADLOCK on this Server 2003.
We now have our own minimal and complete code that reproduces the issue. However, the .exe we've licensed that is being executed by the process has confidentiality clauses that prevent us from posting. I realize that doesn't help the experts here.
THE ONE HINT we've encountered is that when run via the Visual Studio 2013 debugger installed on the actual server, the process doesn't deadlock/hang, while invoking the process from a browser OUTSIDE the server does. And oddly -- from a browser ON THE 2012 SERVER we can't connect to that test page -- the browser just says "connecting" and eventually times out (however, other sites hosted by the same server / same IIS 8 CAN BE REACHED from a browser on the server!)
Since the same command line parameters manually run from either an admin command shell or a non-admin command shell works perfectly, it's hard to believe it's a 64-bit / WOW64 problem with this 32-bit executable or it's required DLLs. We continue to search for places our permissions may be causing problems (the process needs to write to a temp folder, which we've placed at c:\temp, for now).
Without a good Minimal, Complete, and Verifiable code example, it's impossible to answer completely.
What I can tell you is that your code was always broken, and always had the potential for deadlock. You fail to read anything from the process until the process exits, but the process may not be able to exit, if it writes so much data to stdout that the buffer fills and blocks the process.
If you haven't recompiled anything, but have found that you see deadlock now when you didn't before, then the most likely explanation is that the process you're starting writes more to stdout than it used to. I.e. all of the output used to fit in the buffer before, but now it doesn't. (I guess it's also possible the buffer size was reduced in the newer OS, but that seems unlikely to me.)
You should go ahead and move the call to ReadToEnd(). In fact, you should do away with the WaitForExit() altogether. If you are calling ReadToEnd(), that won't complete until the process has in fact exited anyway, so calling WaitForExit() afterwards would be pointless.

Why does Process.Start show an error message box, even though I redirect the standard error?

Why does Process.Start show an error message box, even though I redirect the standard error?
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.Arguments = Optimizer.GetArgumentsString();
startInfo.FileName = ProjectSettings.OptimizerExe;
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
process = System.Diagnostics.Process.Start(startInfo);
string output = process.StandardOutput.ReadToEnd();
string outpute = process.StandardError.ReadToEnd();
process.WaitForExit();
The call System.Diagnostics.Process.Start(startInfo) results in this error message box:
but I don't want that message box to show. If there is an error in the called exe
I want to handle it myself, I don't know where that error message box comes from.
This message box comes right from the process you started.
You could check if there is "console" mode of operation for your process - try to start it from the command line with option for help - ( "/?", "/help",...) or contact the customer support of the company that developed the application.
If it is inhouse applicaiton or you have access to the source code - you can modify it and implement the console mode yourself. There are well known techniques how to do it - I will not describe them here as this would different question :)
If there is no console mode and you have no soure code access - than the process is just not intended to be used like this and you are out of luck. Of course you could make sure a valid license is found and message box does not show - but some other message box can pop up later.
Well, the process you're starting is showing the error box. There's nothing clean you can do about it. It's out of your reach.
The message box exists in a wholy separate message loop, in a completely different process. It has nothing to do with you using Process.Start - if you start the exe using Windows Explorer, it will still show that dialog. If you do have the license file, make sure you set the WorkingDirectory to the correct folder (provided the application actually reads the license from a file) - that might solve your issue.
Redirect standard output will do exactly what it says - it will redirect the standard output pipe. That's basically Console.WriteLine/ReadLine - it does nothing with GUI.
The same way "standard error" is just another pipe. The application obviously doesn't use it to output errors. It's not required too, and it's not used much in GUI applications.
In reality, both standard output and standard error are features of command line applications, not of GUI applications. If the application isn't designed to work from the command line, you ain't gonna make it :)
Oh, and when you redirect standard output/error, you have to actually read it. Otherwise, if they are used by the application, their buffers will get filled and the application will freeze :)

What Does No such interface supported Mean

I am getting an exception on my server side code, which is serving up a silverlight app,
Win32Exception - No such interface supported
Our server side C# code starts up a separate process for a short task because of a third party dll not being thread safe. So the error above occurs in part of the code like this,
Process process = new Process();
ProcessStartInfo processStartInfo = new ProcessStartInfo();
processStartInfo.CreateNoWindow = true;
processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
processStartInfo.FileName =
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin", "PreviewGenerator.exe");
process.StartInfo = processStartInfo;
process.Start(); // THIS IS WHERE THE EXCEPTION OCCURS
process.WaitForExit();
The PreviewGenerator.exe process does not start when it is not working, the exception occurs where the comment is above.
UPDATE:
I have run process monitor on the IIS server when the issue occurs. This shows that the w3wp process does this,
Thread Create
Access the file PreviewGenerator.exe
Hive unloaded (this is the registry)
Thread Exit
And it does this before calling the other process. If I compare this with a the process monitor log when it is working it does this,
Thread Create
Access the file PreviewGenerator.exe
Process Start
Does heaps of stuff with PreviewGenerator.exe including reading / writing / registry, etc.
Process Exit
Hive unloaded
Thread Exit
But process monitor does not show any information as to why the first case doesn't work.
Is there a way I can see why the thread exits prematurely?
Also I think this problem relates to when my server is being loaded up more, and much more memory is being used. How can I prove this?
I had a similar issue, I used
processStartInfo.UseShellExecute = false;
and that fixed it for me.
http://www.progtown.com/topic31343-process-start-processstartinfo-startinfo.html
I found the best thing to do was to create a separate app pool for my application in IIS and set an upper limit for the amount of RAM it could use. Also I found it useful to turn on the 'Generate Recycle Event Log Entry' items under the app pool settings.
You can then go to the system event log and filter out the items with a source of 'WAS' to understand what is going on in the app pools, when they are restarting and when they stop from being idle etc.
I think the main problem in our case is that the IIS box was running out of memory. Tuning the app pools and adding some extra RAM seems to have solved it.

How to control network client pc

In my local network ,I have more than 10 pc.I need to take care all of the pc.I want to know all pc’s hardware informations.I also want to control those pc,Suppose ,at this moment I want to restart one of my client pc.Is it possible in C#.if have any question plz ask.Thanks in advance
I use bellow syntax to execute command.
try
{
// create the ProcessStartInfo using "cmd" as the program to be run,
// and "/c " as the parameters.
// Incidentally, /c tells cmd that we want it to execute the command that follows,
// and then exit.
System.Diagnostics.ProcessStartInfo procStartInfo =
new System.Diagnostics.ProcessStartInfo("cmd", "/c " + "shutdown /r /m \\172.16.1.3 /t 1 /");
// The following commands are needed to redirect the standard output.
// This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
// Display the command output.
Console.WriteLine(result);
}
catch (Exception objException)
{
// Log the exception
}
Using the above code I get the message "The network path was not found."
Pls check the url.
http://support.microsoft.com/kb/317371
If you want to make a program which u can able to get the remote system information. You have to use Microsoft's Remoting.Here we can able to create an object in the remote system and we can able to control it.
It is possible to get System's information by executing the System.Diagnostics.ProcessStartInfo.
It is possible to get system information using "systeminfo" .It is possible to take the output using C#
Pls chk the this.
I hope this will be useful for you.
I don't think this is a C# question, cause this can be done much more elegant with things like Group Policy Editor, System Management Server, System Center Operations Manager, etc.
To do some simple tasks on a remote machine you can take a look into the PsTools.
With those requirements my first stop would be WMI. There's for example the Win32_OperatingSystem class with its Reboot and Shutdown methods and the Win32_Processor with all kinds of information about the CPU.
This MSDN section shows you how to use it from .Net: Getting Started Accessing WMI Data
This MSDN section has quite a lot of short VBScript samples for doing various things using WMI, and even if the code is different, at least you can see which WMI classes/methods/properties you should be looking at: WMI Tasks for Scripts and Applications
Please note RB's comment though, you'll need to have the correct permissions for it to work.
Edit: Forgot that since you'll want to connect to other computers, this sample will be useful: How To: Connect to a Remote Computer

Can I stop an IIS?

In a .NET windows application to to modify a remote machine config file that is used by an ASP.NET application. However, I keep getting the error:
System.IO.IOException: The process cannot access the file '[file name]' because it is being used by another process.
Now, this may not be the problem, but I'm figuring that if I can stop the IIS, then I can modify the machine config file (without getting the exception), and then I can restart the IIS using this code:
Process proc = new Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.FileName = "iisreset";
proc.StartInfo.Arguments = serverName;
try
{
proc.Start();
proc.WaitForExit();
...
1) Is there a way to stop the IIS without restarting it, and 2) Doe this approach to changing the server.config file even make sense?
(note, I am modifying the file with regular expressions search and replace; is this a problem?)
You should be able to do something like this. I don't have windows, so I can't check the exact name of the service, but I think it is "IISADMIN" or "w3svc". Remember this should be the service name and not the display name you see in the service control panel.
ServiceController controller = new ServiceController();
controller.MachineName = "."; // or the remote machine name
controller.ServiceName = "IISADMIN"; // or "w3svc"
string status = controller.Status.ToString();
// Stop the service
controller.Stop();
// Start the service
controller.Start();
You can also use
net stop w3svc
or
net stop IISADMIN
from the commandline or in your process in your code
Strange. A .config file should not be locked exclusively.
But to answer your question, you can also use the net command for this:
net stop w3svc
to stop the www service, and
net start w3svc
to start it again.
You can also do this programmatically as described by #monkeyp
Note that I would advice against this and first try to determine (and resolve) the cause of the lock as described by #RichardOD.
Using System.Diagnostics;
//to stop ISS
ProcessStartInfo startInfo = new ProcessStartInfo("iisreset.exe", " /stop");
System.Diagnostics.Process.Start(startInfo);
//to start ISS
ProcessStartInfo stopInfo = new ProcessStartInfo("iisreset.exe", " /start");
System.Diagnostics.Process.Start(stopInfo);
You can use the IISRESET /STOP command.
If you type IISRESET /? you will get a list of other available options.
[Edit: Pass the "/STOP" switch as the arguments property on the process' startinfo object.]
Should be "iisreset /STOP" to stop the services, then "iisreset /START" to restart them.
Use a tool like wholockme or unlocker to find the root cause of the locking.
Update- another option is to use Process Explorer (thanks fretje)- this is a good option as lots of developers have this utility on their PC.
You can often just recycle or stop/start the Application Pool IIS is running, rather than restarting IIS altogether.

Categories

Resources