You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET Core Web应用中启停并监控常驻外部EXE程序?

实现.NET Core Web应用管理常驻EXE的方案

核心思路

用System.Diagnostics.Process管理目标EXE进程,结合.NET Core的IHostApplicationLifetime生命周期事件,确保Web应用启动时自动拉起EXE、终止时自动停止EXE;再通过API暴露进程状态查询和操作接口,前端UI调用这些接口实现交互。

步骤分解

1. 封装进程管理单例服务

创建全局唯一的进程管理服务,统一控制EXE的启停状态:

public class ExeProcessManager
{
    private Process _exeProcess;
    private readonly string _exePath;
    private readonly ILogger<ExeProcessManager> _logger;

    public ExeProcessManager(IConfiguration config, ILogger<ExeProcessManager> logger)
    {
        _exePath = config["ExeSettings:TargetPath"]; // 从配置文件读取EXE路径
        _logger = logger;
    }

    public bool IsRunning => _exeProcess?.HasExited == false;

    public void Start()
    {
        if (IsRunning) return;

        _exeProcess = new Process
        {
            StartInfo = new ProcessStartInfo(_exePath)
            {
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true
            },
            EnableRaisingEvents = true
        };

        // 监听进程意外退出事件
        _exeProcess.Exited += (sender, e) =>
        {
            _logger.LogWarning("目标EXE意外退出,退出码:{Code}", _exeProcess.ExitCode);
            _exeProcess.Dispose();
            _exeProcess = null;
        };

        // 捕获EXE输出和错误日志
        _exeProcess.OutputDataReceived += (sender, e) =>
        {
            if (!string.IsNullOrEmpty(e.Data))
                _logger.LogInformation("EXE输出:{Content}", e.Data);
        };
        _exeProcess.ErrorDataReceived += (sender, e) =>
        {
            if (!string.IsNullOrEmpty(e.Data))
                _logger.LogError("EXE错误:{Content}", e.Data);
        };

        _exeProcess.Start();
        _exeProcess.BeginOutputReadLine();
        _exeProcess.BeginErrorReadLine();
        _logger.LogInformation("已启动目标EXE");
    }

    public void Stop()
    {
        if (!IsRunning) return;

        try
        {
            _exeProcess.Kill(true); // 终止进程及子进程
            _exeProcess.WaitForExit(5000); // 等待5秒确保完全退出
            _logger.LogInformation("已停止目标EXE");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "停止EXE时发生错误");
        }
        finally
        {
            _exeProcess?.Dispose();
            _exeProcess = null;
        }
    }

    public void Restart()
    {
        Stop();
        Thread.Sleep(1000); // 短暂延迟避免进程未完全退出就重启
        Start();
    }
}

2. 集成Web应用生命周期

在Program.cs中注册服务,并绑定应用启动/停止事件:

var builder = WebApplication.CreateBuilder(args);

// 注册进程管理服务为单例
builder.Services.AddSingleton<ExeProcessManager>();

var app = builder.Build();

// 获取生命周期服务和进程管理器实例
var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
var processManager = app.Services.GetRequiredService<ExeProcessManager>();

// 应用启动完成后自动启动EXE
lifetime.ApplicationStarted.Register(() =>
{
    processManager.Start();
});

// 应用关闭前自动停止EXE
lifetime.ApplicationStopping.Register(() =>
{
    processManager.Stop();
});

// 注册API控制器
app.MapControllers();

// 配置静态文件(用于托管UI页面)
app.UseStaticFiles();

app.Run();

3. 暴露API接口供UI调用

创建控制器提供进程操作接口:

[ApiController]
[Route("api/process")]
public class ProcessController : ControllerBase
{
    private readonly ExeProcessManager _processManager;

    public ProcessController(ExeProcessManager processManager)
    {
        _processManager = processManager;
    }

    [HttpGet("status")]
    public IActionResult GetStatus()
    {
        return Ok(new { IsRunning = _processManager.IsRunning });
    }

    [HttpPost("start")]
    public IActionResult StartProcess()
    {
        _processManager.Start();
        return Ok("已启动目标进程");
    }

    [HttpPost("stop")]
    public IActionResult StopProcess()
    {
        _processManager.Stop();
        return Ok("已停止目标进程");
    }

    [HttpPost("restart")]
    public IActionResult RestartProcess()
    {
        _processManager.Restart();
        return Ok("已重启目标进程");
    }
}

4. UI层实现交互

在wwwroot目录下创建静态页面,调用API实现状态展示和操作:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>EXE进程管理</title>
    <style>
        .status-running { color: green; }
        .status-stopped { color: red; }
        button { margin: 0 8px; padding: 6px 12px; }
    </style>
</head>
<body>
    <h2>目标EXE状态:<span id="status" class="status-stopped">已停止</span></h2>
    <div>
        <button id="startBtn">启动</button>
        <button id="stopBtn">停止</button>
        <button id="restartBtn">重启</button>
    </div>

    <script>
        // 每秒刷新一次状态
        setInterval(updateStatus, 1000);

        async function updateStatus() {
            const res = await fetch('/api/process/status');
            const data = await res.json();
            const statusEl = document.getElementById('status');
            if (data.IsRunning) {
                statusEl.textContent = "运行中";
                statusEl.className = "status-running";
            } else {
                statusEl.textContent = "已停止";
                statusEl.className = "status-stopped";
            }
        }

        // 绑定按钮事件
        document.getElementById('startBtn').addEventListener('click', async () => {
            await fetch('/api/process/start', { method: 'POST' });
            updateStatus();
        });

        document.getElementById('stopBtn').addEventListener('click', async () => {
            await fetch('/api/process/stop', { method: 'POST' });
            updateStatus();
        });

        document.getElementById('restartBtn').addEventListener('click', async () => {
            await fetch('/api/process/restart', { method: 'POST' });
            updateStatus();
        });

        // 页面加载时初始化状态
        updateStatus();
    </script>
</body>
</html>

注意事项

  • 权限配置:确保Web应用的运行账户有足够权限启动目标EXE,涉及系统级程序时需提升权限。
  • 异常重启:如果需要EXE意外退出后自动重启,可在Exited事件中调用Start方法。
  • 跨平台适配:部署到Linux/macOS时,需调整ProcessStartInfo的配置(比如CreateNoWindow在Linux下无效)。
  • 日志监控:建议将EXE的输出和错误日志持久化,方便排查问题。

内容的提问来源于stack exchange,提问作者Anthony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:37:02