我有一个 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();
}
}
从技术上讲,您只需调用
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;
}
当然,如果这是异步的,那么等待它在方法内部退出是没有意义的,因此您只需等待或检查它是否已在此方法外部退出。
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();
}
}
}
如果这不是您想要的,请搜索提到的线程以获取更多方法,它提供了很多方法。
CloseMainWindow
类的
System.Diagnostics.Process
方法?当我寻找一种从 C# 向另一个进程发送 WM_CLOSE 消息的方法时,我偶然发现了它。编辑:
如果主窗口被“阻止”(例如被打开的模式窗口或对话框阻止),
CloseMainWindow
似乎不起作用。您可以研究向应用程序进程显式发送 WM_CLOSE 或 WM_DESTROY 消息的策略。但我不能保证它是否会按照您想要/期望的方式工作。我已经很长时间没有使用这种 Windows 消息功能了。
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);