【问题标题】:How to run custom code when "Start Debugging" in Visual Studio and attach to debugger如何在 Visual Studio 中“开始调试”时运行自定义代码并附加到调试器
【发布时间】:2018-09-14 13:14:47
【问题描述】:

VS Code 似乎有一个名为 Launch.json 的文件,用于自定义运行应用程序进行调试时发生的情况。 我们如何为 Visual Studio 做这件事? 我的目标是在没有 VS Docker 工具的情况下运行 docker-compose,然后在容器启动后,告诉 VS 附加到容器。

我的问题并不特定于这种情况,它也可能是另一种使用调试器场景运行的自定义方式。 理想情况下,我可以只运行一些命令来构建项目,运行项目,然后告诉 VS 附加到它并将该逻辑与 VS 相关联。

【问题讨论】:

  • 你能从VIad的建议中得到有用的信息吗?或者您想在项目属性中使用 Pre/Post Build 运行某些命令?
  • @JackZhai-MSFT,我仍在尝试这样做,但使用 Docker 具有挑战性,因为我必须运行多个命令。 1 Docker 组成,2 运行远程调试器,3 以某种方式附加到在 docker 实例中运行的远程调试器。目前,我正试图指向一个 PowerShell 脚本以获得更大的灵活性。
  • 我仍然不知道如何通过脚本使 VS 附加到该远程进程
  • @JackZhai-MSFT,我在这里发布了我想出的解决方案。我真的希望有一种更简单的方法来控制 VS 实例。用于此的 PowerShell 模块将非常棒。

标签: visual-studio debugging ide remote-debugging


【解决方案1】:

在解决方案资源管理器中右键单击项目;选择“属性”。 选择“调试”节点。填写“Command”、“Command Arguments”(如果需要),并将“Attach”设置为 true。

【讨论】:

  • 你是怎么做到的? “命令”处已经有“$(TargetPath)”内容。这代表生成的可执行文件。请问在启动可执行文件之前如何运行自定义命令?
【解决方案2】:

根据 Vlad 和 Jack 的回答,我想出了以下解决方案。 为了在我按下运行按钮时运行我自己的代码,我设置了一个带有自定义启动设置的空白命令行项目。

{
  "profiles": {
    "Build": {
      "commandName": "Executable",
      "executablePath": "powershell",
      "commandLineArgs": ".\\DebugRun.ps1",
      "workingDirectory": "."
    }
  }
}

每当我按下运行时,它都会使用 PowerShell 运行 DebugRun.ps1 脚本。 这是我在DebugRun.ps1 中输入的内容。

docker-compose -f "./docker-compose.debug.yml" --no-ansi up -d --force-recreate --build

Start-Sleep -Seconds 5

$appId = ((docker ps --filter "ancestor=employeemapapp:debug")[1] -split " ")[0]
$apiId = ((docker ps --filter "ancestor=employeemapapi:debug")[1] -split " ")[0]

$appIp = (docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $appId)
$apiIp = (docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $apiId)

docker exec -d $appId C:\\remote_debugger\\x64\\msvsmon.exe /noauth /anyuser /silent /nostatus /noclrwarn /nosecuritywarn /nofirewallwarn /nowowwarn /timeout:214748364
docker exec -d $apiId C:\\remote_debugger\\x64\\msvsmon.exe /noauth /anyuser /silent /nostatus /noclrwarn /nosecuritywarn /nofirewallwarn /nowowwarn /timeout:214748364

$appTarget = $appId + ":4022"
$apiTarget = $apiId + ":4022"

#Parameters
## 1: Solution Name is used to run the code only to the VS instance that has the Solution open
## 2: Transportation method for remote debugger
## 3: Target is the hostname/IP/... to the target where remote debugging is running
## 4: The process name you want to attach tos
./RemoteDebugAttach.exe "EmployeeMap.sln" "Remote (no authentication)" $appTarget "dotnet.exe"
./RemoteDebugAttach.exe "EmployeeMap.sln" "Remote (no authentication)" $apiTarget "dotnet.exe"

Write-Host "Api:" $apiIp
Write-Host "App:" $appIp
$apiUrl = "http://$apiIp/api/employees"
$appUrl = "http://$appIp"

start $apiUrl
start $appUrl

Read-Host "Press any key to quit"

./RemoteDebugDetach.exe EmployeeMap.sln "dotnet.exe"

docker exec -d $appId C:\\remote_debugger\\x64\\utils\\KillProcess.exe msvsmon.exe
docker exec -d $apiId C:\\remote_debugger\\x64\\utils\\KillProcess.exe msvsmon.exe

docker-compose -f "./docker-compose.debug.yml" --no-ansi down 

此脚本执行以下操作:

  • 通过 docker-compose 调出我的 docker 容器
  • 获取容器 ID、IP 等
  • 在容器内启动远程调试器实例
  • 使用自定义可执行文件 (RemoteDebugAttach) 附加到容器内的 dotnet.exe 进程
  • 打开浏览器以浏览从容器提供的网站
  • 等待任何按键来关闭基础架构
  • 使用自定义可执行文件从进程中分离
  • 杀死 docker 容器上的远程调试器
  • 拆下容器

自定义可执行文件来自一个单独的解决方案,我刚刚在其中构建了一些命令行应用程序。 我使用source 中的代码让所有 VS 实例在机器上运行。 并将其与此代码结合起来附加:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        string solutionName = Ask(args, 0, "Solution name?");
        string transportName = Ask(args, 1, "Transport name?");
        string target = Ask(args, 2, "Target machine?");
        string processName = Ask(args, 3, "Process Name?");


        var instances = Msdev.GetIDEInstances(true);
        var dte = (DTE2)instances.Find(d => d.Solution.FullName.EndsWith(solutionName, StringComparison.InvariantCultureIgnoreCase));
        var debugger = dte.Debugger as Debugger2;
        var transports = debugger.Transports;
        Transport transport = null;
        foreach(Transport loopTransport in transports)
        {
            if(loopTransport.Name.Equals(transportName, StringComparison.InvariantCultureIgnoreCase)) // "Remote (no authentication)")
            {
                transport = loopTransport;
                break;
            }
        }

        Processes processes = debugger.GetProcesses(transport, target); // "172.24.50.15:4022");
        foreach(Process process in processes)
        {
            if(process.Name.EndsWith(processName, StringComparison.InvariantCultureIgnoreCase))
            {
                process.Attach();
            }
        }
    }

    static string Ask(string[] args, int index, string question)
    {
        if(args.Length <= index)
        {
            Console.WriteLine(question);
            return Console.ReadLine();
        }

        return args[index];
    }
}

还有以下要分离的:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        string solutionName = Ask(args, 0, "Solution name");
        string processName = Ask(args, 1, "Process Name?");

        var instances = Msdev.GetIDEInstances(true);

        var dte = (DTE2)instances.Find(d => d.Solution.FullName.EndsWith(solutionName, StringComparison.InvariantCultureIgnoreCase));
        var debugger = dte.Debugger as Debugger2;

        Processes processes = debugger.DebuggedProcesses;
        foreach (Process2 process in processes)
        {
            if (process.Name.EndsWith(processName, StringComparison.InvariantCultureIgnoreCase))
            {
                process.Detach(false);
            }
        }
    }

    static string Ask(string[] args, int index, string question)
    {
        if (args.Length <= index)
        {
            Console.WriteLine(question);
            return Console.ReadLine();
        }

        return args[index];
    }
}

我更喜欢在 PowerShell 中使用此代码,因为它更容易复制到其他项目 + 编辑。尽管在 PowerShell 中,我根本无法获得正确的代码来执行,即使使用反射将某些代码应用到 COM 对象时也是如此。

我希望它可以帮助一些想要在 VS 中构建自己的自定义流程的人。 谢谢弗拉德和杰克。

【讨论】:

  • 这是一个非常核心的解决方案来完成这个
  • @tacos_tacos_tacos 我同意。这很痛苦,但根据您的开发团队的用例可能值得。我希望它更简单。
【解决方案3】:

如果你想通过脚本附加到进程调试,你可以考虑使用powershell。

或者据我所知,我们可以自定义附加到进程的代码。

Attach debugger in C# to another process

但如果非要使用VS IDE调试功能,我们经常使用远程调试工具:https://msdn.microsoft.com/library/y7f5zaaa.aspx

【讨论】:

  • 嗨,杰克,谢谢。我已经准备好启动 docker 容器的脚本,并在容器上启动远程调试器服务器。我看到您引用的 SO 帖子仅适用于本地流程,但这可能是一个足够好的起点让我弄清楚:)
  • 我可以通过[System.Runtime.InteropServices.Marshal]::GetActiveObject("VisualStudio.DTE.15.0")获取VS实例,但是我无法将其转换为DTE2,也就是说我无法访问Debugger2.Transports进行远程调试脚本。我更愿意留在 PowerShell 中,但我认为我必须为它编写一个控制台应用程序
猜你喜欢
  • 1970-01-01
  • 2020-01-06
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 2023-03-18
  • 2020-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多