在 IIS Express 停止后停止 npm task/script

Stop npm task/script, after IIS Express stop

所以这很有趣。我有一个使用 EntityFrameworkCore 和 VueJS 的 dotnetcore 3 项目。正确的。我的 Startup.cs:Configure(app,env) 中有一个如下所示的声明:

app.UseSpa(spa =>
{
  if (env.IsDevelopment())
    spa.Options.SourcePath = "ClientApp";
  else
    spa.Options.SourcePath = "dist";

  if (env.IsDevelopment())
    {
      spa.UseVueCli(npmScript: "serve", port: 4444, forceKill: true);
    }
});

如您所见,我已手动将端口指定为 4444,如果我不这样做,应用程序将尝试 运行 端口 8080 或 [=16] =] 直到应用程序命中机器上的空闲端口。当您只 运行 应用程序一次然后它永远不会崩溃或 Visual Studio 永远不会崩溃或者您必须停止调试代码以管理项目文件结构时,这是可以的。.你明白我的意思.. 在开发中,您永远不会只触发一次命令并完成它。至少在我的经验中不是。

但是,尽管如此,这就是此设置假定您所做的,因为当 IIS Express 服务关闭时它永远不会停止 npm 脚本,但它会尝试重新启动 VueJS 应用程序,在我的例子中,在同一时间本地主机端口,它确保没有正确建立与重新启动的应用程序的连接,从而导致混乱。除非你通过 windows 终端杀死之前的 npm-script 任务。

所以我的问题是 - 当我停止我的 IIS Express 服务器时,有人知道如何从 运行 停止脚本并终止使它保持活动状态的任务吗?老实说,这让我有点莫名其妙:)

中间件class如果有人感兴趣:)

#region Assembly VueCliMiddleware, Version=3.1.0.0, Culture=neutral, PublicKeyToken=null
// C:\Users\<USER>\.nuget\packages\vueclimiddleware.1.1\lib\netcoreapp3.1\VueCliMiddleware.dll
#endregion

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.SpaServices;
using VueCliMiddleware;

namespace VueCliMiddleware
{
    public static class VueCliMiddlewareExtensions
    {
        public static IEndpointConventionBuilder MapToVueCliProxy(this IEndpointRouteBuilder endpoints, string pattern, SpaOptions options, string npmScript = "serve", int port = 8080, ScriptRunnerType runner = ScriptRunnerType.Npm, string regex = "running at", bool forceKill = false);
        public static IEndpointConventionBuilder MapToVueCliProxy(this IEndpointRouteBuilder endpoints, string pattern, string sourcePath, string npmScript = "serve", int port = 8080, ScriptRunnerType runner = ScriptRunnerType.Npm, string regex = "running at", bool forceKill = false);
        public static IEndpointConventionBuilder MapToVueCliProxy(this IEndpointRouteBuilder endpoints, SpaOptions options, string npmScript = "serve", int port = 8080, ScriptRunnerType runner = ScriptRunnerType.Npm, string regex = "running at", bool forceKill = false);
        public static IEndpointConventionBuilder MapToVueCliProxy(this IEndpointRouteBuilder endpoints, string sourcePath, string npmScript = "serve", int port = 8080, ScriptRunnerType runner = ScriptRunnerType.Npm, string regex = "running at", bool forceKill = false);
        public static void UseVueCli(this ISpaBuilder spaBuilder, string npmScript = "serve", int port = 8080, ScriptRunnerType runner = ScriptRunnerType.Npm, string regex = "running at", bool forceKill = false);
    }
}

好的,免责声明:这是一个彻头彻尾的 hack,只有当你事先知道你的端口时才有效(至少,它在我的机器上有效 ;) ),需要 HEAVY 重构,我不提供任何保证。

很少有人知道您可以非常轻松地附加到您的应用程序生命周期,在启动 class:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        lifetime.ApplicationStopping.Register(OnStopping); // <== Magic is here!
    }
    // [Blah blah, yada yada, your super cool code here]
}

private void OnStopping()
{
    // Things to do before application is stopped
}

我的想法是获取正在收听您的 known tcp port(比方说 4444)和 kill it(戏剧性音乐)的进程。

我知道从端口检索 PID 的更快方法是使用 netstat -nao。 OnStopping 代码看起来像这样:

private void OnStopping()
{
    // Following code runs on Windows platform only, 
    // if current platform is something else, we just exit
    if(!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return;

    Process netstat = new Process();
    netstat.StartInfo = new ProcessStartInfo
    {
        FileName = "netstat",
        Arguments = "-nao",
        RedirectStandardOutput = true
    };

    netstat.Start();
    var output = netstat.StandardOutput.ReadToEnd();
    var ports = output.Split('\n');
    var f = ports.FirstOrDefault(p => p.Contains("LISTENING") && p.Contains("127.0.0.1:4444"));
    var pid = int.Parse(f.Split(' ').Last());
    var clientServer = Process.GetProcessById(pid);
    clientServer.Kill();
    clientServer.WaitForExit();
}

请告诉我您的想法,以及它是否适合您。

部分回答(有点)。来自 https://github.com/EEParker/aspnetcore-vueclimiddleware/blob/master/src/VueCliMiddleware/VueDevelopmentServerMiddleware.cs

以下:

if (portNumber < 80)
{
  portNumber = TcpPortFinder.FindAvailablePort();
}
else
{
  // if the port we want to use is occupied, terminate the process utilizing that port.
  // this occurs when "stop" is used from the debugger and the middleware does not have the opportunity to kill the process
  PidUtils.KillPort((ushort)portNumber, forceKill);
}

您可以在本地构建它,然后进行跟踪以查看 if/why 它没有按预期工作。似乎 forceKill 的全部意义在于解决这个问题。