dotnet core 如何优雅地关闭子进程

问题描述 投票:0回答:4

我有一个 dotnet core 2.2 控制台应用程序。
我将其托管为 Windows 服务。
服务启动另一个 dotnet core WebAPI。
问题是,当服务停止时,如何优雅地关闭WebAPI进程?
注意: 我不想使用 Kill() 方法。

示例代码:

public class MyService : IHostedService, IDisposable
{
    private Timer _timer;
    static Process webAPI;

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new Timer(
            (e) => StartChildProcess(),
            null,
            TimeSpan.Zero,
            TimeSpan.FromMinutes(1));

        return Task.CompletedTask;
    }

    public void StartChildProcess()
    {
        try
        {
            webAPI = new Process();
            webAPI.StartInfo.UseShellExecute = false;
            webAPI.StartInfo.FileName = @"C:\Project\bin\Debug\netcoreapp2.2\publish\WebAPI.exe";
            webAPI.Start();
        }
        catch (Exception e)
        {
            // Handle exception
        }
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        // TODO: Add code to stop child process safely

        _timer?.Change(Timeout.Infinite, 0);

        return Task.CompletedTask;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }
}
c# asp.net-core asp.net-core-webapi asp.net-core-2.2 windows-process
4个回答
1
投票

从技术上讲,您只需调用

Process.Kill()
即可立即关闭该进程。然而,很多时候这并不是正确的方法,因为 WebAPI 可能正在进行重要操作,而您无法真正判断这些操作何时发生,并且
Process.Kill()
并不真正被认为是“优雅的”。

最谨慎的做法是告诉进程您希望尽早关闭它,然后允许 WebAPI 在退出之前清理内容。如果您正在设计 WebAPI,那就更好了,因为这样您就可以决定如何做到这一点。仅在绝对必要时才拨打 Kill()

当然,您可以通过多种方式做到这一点。我想到的是定期检查并向 WebAPI 发送 CTRL+C 输入的套接字。

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; }

当然,如果这是异步的,那么等待它在方法内部退出是没有意义的,因此您只需等待或检查它是否已在此方法外部退出。


0
投票
github 上有很多关于此问题的帖子,请考虑帖子

7426

解决方案在这里找到:

StartAndStopDotNetCoreApp,program.cs的示例代码为:

using System; using System.IO; using System.Diagnostics; namespace StartAndStopDotNetCoreApp { class Program { static void Main(string[] args) { string projectPath = @"C:\source\repos\StartAndStopDotNetCoreApp\WebApplication"; string outputPath = @"C:\Temp\WebApplication"; Console.WriteLine("Starting the app..."); var process = new Process(); process.StartInfo.WorkingDirectory = projectPath; process.StartInfo.FileName = "dotnet"; process.StartInfo.Arguments = $"publish -o {outputPath}"; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.Start(); process.WaitForExit(); process.Close(); process.Dispose(); process = new Process(); process.StartInfo.WorkingDirectory = outputPath; process.StartInfo.FileName = "dotnet"; process.StartInfo.Arguments = $"{projectPath.Split(@"\")[projectPath.Split(@"\").Length - 1]}.dll"; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = false; process.StartInfo.RedirectStandardOutput = true; process.Start(); Console.WriteLine("Press anything to stop..."); Console.Read(); process.Kill(); } } }

如果这不是您想要的,请搜索提到的线程以获取更多方法,它提供了很多方法。


0
投票
也许可以使用

CloseMainWindow

 类的 
System.Diagnostics.Process
 方法?当我寻找一种从 C# 向另一个进程发送 WM_CLOSE 消息的方法时,我偶然发现了它。

编辑:

如果主窗口被“阻止”(例如被打开的模式窗口或对话框阻止),

CloseMainWindow

 似乎不起作用。

您可以研究向应用程序进程显式发送 WM_CLOSE 或 WM_DESTROY 消息的策略。但我不能保证它是否会按照您想要/期望的方式工作。我已经很长时间没有使用这种 Windows 消息功能了。


0
投票
也许看看

MedallionShell。它是多平台的,并且有一个 TrySignalAsync(CommandSignal.ControlC)

 方法,您可以使用它来正常关闭另一个应用程序。可能存在限制,但它适用于等待 
Ctrl + C
 信号的 ASP.Net Core 应用程序。

示例:

var command = Command.Run("dotnet", "run", "--project", "C:\MyRepo\MyProj\MyProj.csproj"); // Implementation details here await command.TrySignalAsync(CommandSignal.ControlC);
    
© www.soinside.com 2019 - 2024. All rights reserved.