1

我有一个 dotnet core 2.2 控制台应用程序。
我将它作为 Windows 服务托管。
服务启动另一个 dotnet 核心 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();
    }
}
4

3 回答 3

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

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

于 2019-05-16T06:34:19.263 回答
0

github上有很多关于这个问题的帖子,请考虑post 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();
        }
    }
}

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

于 2019-05-16T06:18:16.117 回答
0

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

编辑:

CloseMainWindow如果主窗口被“阻止”,例如被打开的模式窗口或对话框,则似乎不起作用。

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

于 2019-05-16T06:45:26.073 回答