tags:

views:

390

answers:

5

I need to start an external process from my web application. This means using System.Diagnostics.ProcessStartInfo to call out and execute a console app (exe). But I then need to somehow make sure nothing went wrong during it's execution and know when the application completed its work.

What's the best way to both catch all possible errors and find out when it's completed?

+1  A: 

You're going to have problems with this. ASP.NET web pages run under a tight security context and may not even be able to start an external process.

Also... ASP.NET will recycle (stop/restart all it's processes) "on a whim". This means that at any moment a web page could have its execution aborted.

Have you considered using a job/task scheduler? The one that comes with SQL Server (non-express version) is very good.

NO - ASP.NET will not *at any moment* abort execution of anything. Worker processes can recycle, but in-flight transactions are not lost, unless there is an application error.
Cheeso
This project isn't using SQL server and it's and external tool I'd like to start. It's not scheduled but should be triggered by a user action in the web app.
Riri
+1  A: 

I sure hope you have control of the code for the external application or you are in for a lot of headaches. The MOST important thing to do is make sure there is no way for that application to hang and not terminate.

You can then use the WaitForExit(), ExitCode, StandarError, StandardOut to "catch all possible errors and find out when it's completed"

Al W
+1  A: 

You can't catch any errors from external program. Maximum you can redirect it's output to your own stream and hope that it will write something when it fails/succeed. You can alkso check process exit code using Process.ExitCode.

You can test if process finished using Process.Exited event, or Process.HasExited property.

Also you should note that by default Asp.Net code runs under NETWORK SERVICE process(iis6 and above), so it will have limited permissions and logged in user will not be able to see it's UI.

@rbobby: you can start external process inside Asp.Net code, but it will inherit the security context of the Asp.Net code.

Alex Reitbort
you can use impersonation to change the security context. Also, you can catch everything sent to stdout and stderr from System.Diagnostics.Process
Moose
To use impersonation to change security context you must know username and password. You might also configure AppPool to use different user. But not everyone will let you do it(chenage AppPool or create user).
Alex Reitbort
I said that you can redirect the program output, but if program crashes, it won't help you.
Alex Reitbort
The security is OK. I'm running it under a different account already set by the user of the application pool.
Riri
+1  A: 

You would be better off catching all the output of the console app and storing it somewhere you can show it on a status page, rather than waiting for the app to finish.

As everyone else above has stated, you're going to go through pain otherwise.

Moose
Thanks. Good comment. I'll make it's possible to see the output somehow.
Riri
A: 

It's not so hard with the Process class. Though, the prior poster was correct - you need to be concerned about permissions.

private string RunProcess(string cmd)
{
  System.Diagnostics.Process p; 
  p= new System.Diagnostics.Process();
  if (cmd== null || cmd=="") {
    return "no command given.";
  }
  string[] args= cmd.Split(new char[]{' '});
  if (args== null || args.Length==0 || args[0].Length==0) {
    return "no command provided.";
  }
  p.StartInfo.FileName= args[0];

  if (args.Length>1) {
    int startPoint= cmd.IndexOf(' ');
    string s= cmd.Substring(startPoint, cmd.Length-startPoint);
    p.StartInfo.Arguments= s; 
  }
  p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
  p.StartInfo.RedirectStandardOutput = true;
  p.StartInfo.UseShellExecute = false;

  p.Start();

  // must have the readToEnd BEFORE the WaitForExit(), to avoid a deadlock condition
  string output= p.StandardOutput.ReadToEnd();
  p.WaitForExit();

  return output; 
}
Cheeso
you can replace cmd == null || cmd =="" with string.IsNullOrEmpty(cmd)and args == nullwill always be true.
Sven Hecht