.net core - How to properly kill started process?
As suggested by @mjwills I've updated the process as follows:
class Program
{
static Process webAPI;
static async Task Main(string[] args)
{
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
webAPI = new Process
{
StartInfo = new ProcessStartInfo("dotnet")
{
UseShellExecute = false,
WorkingDirectory = "C:/Project/publish",
Arguments = "WebAPI.dll",
CreateNoWindow = true
}
};
using (webAPI)
{
webAPI.Start();
webAPI.WaitForExit();
}
}
static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
webAPI.Close();
}
}
dotnet core how to shutdown child process gracefully
Technically you could simply call Process.Kill()
in order to immediately shut down the process. However, a lot of the time that is not the way to go simply because the WebAPI might be in middle of important operations and you can't really tell when those actions may be happening and Process.Kill()
is not really considered "graceful".
What would be most prudent to do is to tell the process that you would like for it to shut down at the earliest convenience and then allow for the WebAPI to clean things up before it exits itself. If you are desiging the WebAPI that is even better because that way you can decide on how to do this. Only calling Kill()
when it is absolutely necessary.
You can do that multiple ways of course. Some that come to mind are Sockets that are periodically checked and sending a CTRL+C input to the WebAPI.
public Task StopAsync(CancellationToken cancellationToken)
{
// send request to shut down
// wait for process to exit and free its resources
process.WaitForExit();
process.Close();
process.Dispose();
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
Of course if this is Async then it wouldn't make sense to wait for it to exit inside of the method so you would simply wait or check if it has exited outside of this method.
Children processes created in ASP.NET Core Process gets killed on exit
As I said in my comment, there is a Job Object which is created by ASP.NET core in the out-of-process scenario. The relevant source code portion is here:
https://github.com/aspnet/AspNetCore/blob/master/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/serverprocess.cpp#L89
HRESULT
SERVER_PROCESS::SetupJobObject(VOID)
{
HRESULT hr = S_OK;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = { 0 };
if (m_hJobObject == NULL)
{
....
jobInfo.BasicLimitInformation.LimitFlags =
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
if (!SetInformationJobObject(m_hJobObject,
JobObjectExtendedLimitInformation,
&jobInfo,
sizeof jobInfo))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}
return hr;
}
As per documentation, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE:
Causes all processes associated with the job to terminate when the
last handle to the job is closed.
If you dig the source further, it does not seem to be optional.
Now, you can actually see this by yourself, if you reproduce your steps. Use Process Explorer, and navigate to your dotnet.exe process, this is what it will display:
- note 1: in fact
calc.exe
stays alive (at least in my Windows 10 installation because it's now a WinRT app, so it will not end up as child of dotnet.exe), that's why I usednotepad.exe
- note 2:
iisexpress.exe
also creates a job object, but it's configured as breakaway ok, which means it won't kill child processes. - note 3: if you run from Visual Studio (not my screenshot), you may see an intermediary
VSIISExeLauncher.exe
process betweeniisexpress.exe
anddotnet.exe
. This one also creates a Job Object with 'kill on close' to add to the confusion...
Kill process tree programmatically in C#
This worked very nicely for me:
/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
private static void KillProcessAndChildren(int pid)
{
// Cannot close 'system idle process'.
if (pid == 0)
{
return;
}
ManagementObjectSearcher searcher = new ManagementObjectSearcher
("Select * From Win32_Process Where ParentProcessID=" + pid);
ManagementObjectCollection moc = searcher.Get();
foreach (ManagementObject mo in moc)
{
KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
}
try
{
Process proc = Process.GetProcessById(pid);
proc.Kill();
}
catch (ArgumentException)
{
// Process already exited.
}
}
Update 2016-04-26Tested on Visual Studio 2015 Update 2
on Win7 x64
. Still works as well now as it did 3 years ago.
Added check for system idle process if (pid == 0)
Need to add a reference to the System.Management
namespace, see comment from @MinimalTech below. If you have ReSharper installed, it will offer to do this for you automatically.
The most common use case for this is killing any child processes that our own C# process has started.
In this case, a better solution is to use Win32 calls within C# to make any spawned process a child process. This means that when the parent process exits, any child processes are automatically closed by Windows, which eliminates the need for the code above. Please let me know if you want me to post the code.
Related Topics
How to Save/Download Pdf Embedded in Web Page Without a Pdf Filename
Updating an Object from a List in C#
Return Json, But It Includes Backward Slashes "\", Which I Don't Want
How to Pass Parameter from @Url.Action to Controller Function
How to Format a Number in C# With Commas and Decimals
Most Efficient Way to Compare Two Ienumerables (Or Lists) in Linq
What Is the Correct Way to Compare Char Ignoring Case
Build Query String for System.Net.Httpclient Get
How to Format Number as Money Using Regex
Create a C# Method to Generate Auto Increment Id
Removing Elements from Json Based on a Condition in C#
Algorithm to Detect Overlapping Periods
Get All Children to One List - Recursive C#
Check If Task Is Already Running Before Starting New
How to Send a File Document to the Printer and Have It Print
Add Client Certificate to .Net Core Httpclient
Choosing the Default Value of an Enum Type Without Having to Change Values