дотнет ядро, как корректно завершить дочерний процесс - PullRequest
0 голосов
/ 16 мая 2019

У меня есть консольное приложение 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();
    }
}

Ответы [ 3 ]

1 голос
/ 16 мая 2019

Технически вы можете просто позвонить Process.Kill(), чтобы немедленно завершить процесс.Тем не менее, большую часть времени это не тот путь, потому что WebAPI может быть в середине важных операций, и вы не можете точно сказать, когда эти действия могут происходить, а Process.Kill() на самом деле не считается «изящным».

Что было бы наиболее разумно сделать, это сказать процессу, что вы хотели бы , чтобы он завершился при первой же возможности, а затем разрешить WebAPI убирать вещи до его выхода.сам.Если вы разрабатываете WebAPI, это даже лучше, потому что таким образом вы можете решить, как это сделать.Звонить Kill() только тогда, когда это абсолютно необходимо.

Конечно, вы можете сделать это несколькими способами.Некоторые из них приходят на ум - это сокеты, которые периодически проверяются и отправляют ввод CTRL + C в 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;
    }

Конечно, если это Async, то не имеет смысла ждать его выходавнутри метода, чтобы вы просто подождали или проверили, вышел ли он за пределы этого метода.

0 голосов
/ 16 мая 2019

Возможно, можно использовать метод CloseMainWindow класса System.Diagnostics.Process? Я наткнулся на это, когда искал способ отправить сообщение WM_CLOSE другому процессу из C #.

Edit:

CloseMainWindow не работает, если главное окно «заблокировано», например, открытым модальным окном или диалоговым окном.

Вы можете изучить стратегию явной отправки сообщения WM_CLOSE или WM_DESTROY в процесс приложения. Но я не могу гарантировать, будет ли это работать так, как вы хотите / ожидаете. Я давно не работал с подобными функциями Windows Messages.

0 голосов
/ 16 мая 2019

На github было много тем по этому поводу, рассмотрим сообщение 7426 .

Решение найдено здесь: StartAndStopDotNetCoreApp , пример кода программы .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();
        }
    }
}

Если это не то, что вы ищете, поищите в упомянутой ветке дополнительные способы, они предлагают множество возможностей.

...