代码之家  ›  专栏  ›  技术社区  ›  MistyK

在ASP.NET核心进程中创建的子进程在退出时被杀死

  •  19
  • MistyK  · 技术社区  · 6 年前

    我在ASP.NET核心(.NET框架)中用 Process 班级:

    var process = new Process
                {
                    StartInfo = new ProcessStartInfo(executableDir)
                    {
                        Arguments = commandDefinition.CommandDef.ArgumentsAsString,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        UseShellExecute = false,
                        CreateNoWindow = true,
                        WorkingDirectory = _contentPath,
                    },
                };
    
    process.Start()
    

    据我所知,当父进程(ASP.NET核心)被杀死时,子进程应该保持活动。我使用两个控制台应用程序测试了这种行为,并且子进程在杀死父进程后永远不会被杀死。 但是,当我在ASP.NET核心中生成一个新进程时,当出现以下情况时,子进程将被杀死:

    • IIS回收应用程序。
    • msdeploy发布了新版本的ASP.NET核心应用程序。
    • 当使用dotnet watch并且在到期间重新启动应用程序时 代码更改。

    只有当父级通过任务管理器被杀死时,它才会被杀死。(经过一些测试,情况并非总是如此)

    从上面我怀疑ASP.NET核心中存在一种机制,在成功退出时会杀死所有子进程。它有文件记录吗?有没有办法避免?我找不到关于这种行为的任何信息。

    编辑: 事实上,重拍很容易。

    1. 创建ASP.NET核心项目(.NET框架或.NET核心,无所谓)
    2. 将下面的代码添加到 Startup
    3. 启动Web应用程序。它将在IIS Express下托管。计算过程将开始。现在,要么通过任务管理器终止应用程序,要么通过IIS Express托盘图标关闭它。
    4. 计算过程将被终止。(有时需要尝试刷新脱机网页)
     var process = new Process
     {
          StartInfo = new ProcessStartInfo("calc.exe")
          {
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
                CreateNoWindow = true,
          },
     };
     process.Start();
    

    伊迪丝2:问题似乎出在IIS上。我在launchsettings.json中有两个配置文件。如果我用iisexpress运行它,那么它会关闭,但是当使用第二个时,它会生存。

    "IIS Express": {
          "commandName": "IISExpress",
          "launchBrowser": true,
          "launchUrl": "api/values",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          }
        },
        "WebApplication3Core": {
          "commandName": "Project",
          "launchBrowser": true,
          "launchUrl": "api/values",
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          },
          "applicationUrl": "http://localhost:52135/"
        }
    

    编辑4:

    我用过程监视器做了一些研究,结果如下:

    ss1

    ss2

    ss3

    正如您在SS1中看到的,iisexpress有一个“进程退出”操作,然后有许多不可逆日志,一段时间后,calc.exe有一个进程退出。这和正常出口没什么不同。唯一的区别是后一个日志写着“closefile”和我的web应用的路径,我不知道它的真正含义。 杀死calc.exe的肯定是IIS。我有IIS Express 10.0.14358版本(我发现的服务器版本也是10)

    2 回复  |  直到 6 年前
        1
  •  4
  •   Simon Mourier    6 年前

    正如我在评论中所说,有一个 Job Object 由ASP.NET核心在 out-of-process scenario . 相关的源代码部分如下:

    https://github.com/aspnet/AspNetCore/blob/master/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/serverprocess.cpp#L89

    HRESULT
    SERVER_PROCESS::SetupJobObject(VOID)
    {
        HRESULT                                 hr = S_OK;
        JOBOBJECT_EXTENDED_LIMIT_INFORMATION    jobInfo = { 0 };
    
        if (m_hJobObject == NULL)
        {
          ....
                jobInfo.BasicLimitInformation.LimitFlags =
                    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    
                if (!SetInformationJobObject(m_hJobObject,
                    JobObjectExtendedLimitInformation,
                    &jobInfo,
                    sizeof jobInfo))
                {
                    hr = HRESULT_FROM_WIN32(GetLastError());
                }
            }
        }
    
        return hr;
    }
    

    根据文件, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE :

    使与作业关联的所有进程在 作业的最后一个句柄已关闭。

    如果您进一步挖掘源,它似乎不是可选的。

    现在,如果你复制你的步骤,你可以自己看到这个。使用 Process Explorer ,并导航到dotnet.exe进程,它将显示以下内容:

    enter image description here

    • 注1:事实上 calc.exe 保持活动(至少在我的Windows10安装中,因为它现在是一个WinRT应用程序,所以它不会最终成为dotnet.exe的子级),这就是我使用的原因 notepad.exe
    • 注2: iisexpress.exe 也创建了一个作业对象,但它被配置为分离OK,这意味着它不会杀死子进程。
    • 注3:如果您从Visual Studio(而不是我的屏幕截图)运行,您可能会看到一个中介 VSIISExeLauncher.exe 过程之间 IISExchange dotnet.exe . 这一个还创建了一个“关闭时终止”的作业对象,增加了混乱…
        2
  •  4
  •   Alexandru Clonțea    6 年前

    编辑

    解决方案不适用于notepad.exe-我将尝试查看是否存在 任何基于西蒙回答的选项,比如为什么会发生这种行为

    旧答案(待删除)

    我现在必须为编写这段代码而洗手,但我认为如果这是您在上下文中需要的话,您可以绕过这个限制。我建议不要运行外部流程,尤其是 来自“Web服务器”。这是自找麻烦。将进程替换为恶意人员、凭证升级、由于语法更改而导致的意外行为等等。

    无论如何,这可能对您有效(在两者之间插入cmd.exe,以尝试破坏子-父关系):

    var process = new Process
    {
      StartInfo = new ProcessStartInfo 
          { 
             FileName ="cmd.exe",  
             Arguments = "/c calc.exe", 
             WindowStyle =  ProcessWindowStyle.Hidden
          }
    };
    
    process.Start();
    
    推荐文章