Tuesday, April 12, 2022

[SOLVED] Remote debugging with VS Code on Windows to a Raspberry Pi

Issue

I need help to setup my vscode in order to deploy and debug a dotnet application on my RPi 4 (Raspberry Pi OS x64), because I'm not able to attach the vscode debugger.

The application is correctly built and deployed on my RPi, and I can run it via ssh using the command dotnet ~/MyFirstApp/MyFirstApp.dll, but when I try to run it using the debugging function of vscode it returns the following error:

Could not execute because the specified command or file was not found.
Possible reasons for this include:
  * You misspelled a built-in dotnet command.
  * You intended to execute a .NET program, but dotnet-~/MyFirstApp/MyFirstApp.dll does not exist.
  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.

Here all the files:

  • MyFirstApp.cs

    Console.WriteLine("Hello, World!");
    
  • MyFirstApp.csproj

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <ImplicitUsings>enable</ImplicitUsings>
        <Nullable>enable</Nullable>
      </PropertyGroup>
    </Project>
    
  • .vscode/launch.json

    {
      "version": "0.2.0",
      "configurations": [
          {
              "name": ".NET Core Launch (remote)",
              "type": "coreclr",
              "request": "launch",
              "preLaunchTask": "RaspberryPiDeploy",
              "program": "~/.dotnet/dotnet",
              "args": ["~/${workspaceFolderBasename}/${workspaceFolderBasename}.dll"],
              "cwd": "~/${workspaceFolderBasename}",
              "stopAtEntry": false,
              "console": "internalConsole",
              "pipeTransport": {
                  "pipeCwd": "${workspaceFolder}",
                  "pipeProgram": "ssh",
                  "pipeArgs": [
                      "[email protected]"
                  ],
                  "debuggerPath": "~/vsdbg/vsdbg"
              }
          }
      ]
    }
    
  • .vscode/tasks.json

    {
      "version": "2.0.0",
      "tasks": [
          {
              "label": "build",
              "command": "dotnet",
              "type": "process",
              "args": [
                  "build",
                  "${workspaceFolder}/MyFirstApp.csproj",
                  "/property:GenerateFullPaths=true",
                  "/consoleloggerparameters:NoSummary"
              ],
              "problemMatcher": "$msCompile"
          },
          {
              "label": "RaspberryPiPublish",
              "command": "sh",
              "type": "shell",
              "dependsOn": "build",
              "windows": {
                  "command": "cmd",
                  "args": [
                      "/c",
                      "\"dotnet publish -r linux-arm64 -o bin\\linux-arm64\\publish --no-self-contained\""
                  ],
                  "problemMatcher": []
              }
    
          },
          {
              "label": "RaspberryPiDeploy",
              "type": "shell",
              "dependsOn": "RaspberryPiPublish",
              "presentation": {
                  "reveal": "always",
                  "panel": "new",
                  "close": true
              },
              "windows": {
                  "command": "scp -r bin\\linux-arm64\\publish\\* [email protected]:${workspaceFolderBasename}"
              },
              "problemMatcher": []
          }
      ]
    }
    

Solution

It is possible to apply two different types of build: Self-contained and Framework-dependent.

  1. The Self-contained build requires to run chmod +x on MyFirstApp (thanks to @PMF's suggestion):

    • launch.json

      {
             "name": ".NET Remote Launch - Self-contained",
             "type": "coreclr",
             "request": "launch",
             "preLaunchTask": "RaspberryPiDeploySelfContained",
             "program": "~/MyFirstApp/MyFirstApp",
             "args": [],
             "cwd": "~/MyFirstApp",
             "stopAtEntry": false,
             "console": "internalConsole",
             "pipeTransport": {
                 "pipeCwd": "${workspaceRoot}",
                 "pipeProgram": "ssh",
                 "pipeArgs": [
                     "[email protected]"
                 ],
                 "debuggerPath": "~/vsdbg/vsdbg"
             }
      }
      
    • tasks.json

      {
             "label": "RaspberryPiPublishSelfContained",
             "command": "sh",
             "type": "shell",
             "dependsOn": "build",
             "windows": {
                 "command": "cmd",
                 "args": [
                     "/c",
                     "\"dotnet publish -r linux-arm64 -o bin\\linux-arm64\\publish\""
                 ],
                 "problemMatcher": []
             }
      
         },
         {
             "label": "RaspberryPiDeploySelfContained",
             "type": "shell",
             "dependsOn": "RaspberryPiPublishSelfContained",
             "presentation": {
                 "reveal": "always",
                 "panel": "new",
                 "close": true
             },
             "windows": {
                 "command": "scp -r bin\\linux-arm64\\publish\\* [email protected]:${workspaceFolderBasename}; ssh [email protected] chmod +x \"${workspaceFolderBasename}/${workspaceFolderBasename}\""
             },
             "problemMatcher": []
      }
      

    This solution works, but, considering that it is a "self-contained" app, it requires more time to copy all the dependencies and requires more disk space.

  2. The Framework-dependent solution requires to copy fewer files (less time and disk space to deploy and test it):

    • launch.json: I had to setup the args field providing the path as /home/pi/MyFirstApp/MyFirstApp.dll, I can't figure out why, but giving the path as ~/MyFirstApp/MyFirstApp.dll gives back the error Could not execute because the specified command or file was not found.

      {
             "name": ".NET Remote Launch - Framework-dependent",
             "type": "coreclr",
             "request": "launch",
             "preLaunchTask": "RaspberryPiDeploy",
             "program": "~/.dotnet/dotnet",
             "args": ["/home/pi/MyFirstApp/MyFirstApp.dll"],
             "cwd": "~/MyFirstApp",
             "stopAtEntry": false,
             "console": "internalConsole",
             "pipeTransport": {
                 "pipeCwd": "${workspaceRoot}",
                 "pipeProgram": "ssh",
                 "pipeArgs": [
                     "[email protected]"
                 ],
                 "debuggerPath": "~/vsdbg/vsdbg"
             }
      }
      
    • tasks.json

      {
             "label": "RaspberryPiPublish",
             "command": "sh",
             "type": "shell",
             "dependsOn": "build",
             "windows": {
                 "command": "cmd",
                 "args": [
                     "/c",
                     "\"dotnet publish -r linux-arm64 -o bin\\linux-arm64\\publish --no-self-contained\""
                 ],
                 "problemMatcher": []
             }
         },
         {
             "label": "RaspberryPiDeploy",
             "type": "shell",
             "dependsOn": "RaspberryPiPublish",
             "presentation": {
                 "reveal": "always",
                 "panel": "new",
                 "close": true
             },
             "windows": {
                 "command": "scp -r bin\\linux-arm64\\publish\\* [email protected]:\"~/${workspaceFolderBasename}\""
             },
             "problemMatcher": []
      }
      


Answered By - gpare
Answer Checked By - Gilberto Lyons (WPSolving Admin)