RaspberryPi(Raspbian)上で動く.NET Core2.1アプリをリモートデバッグする

# はじめに
こんにちは。

スマートメーターからBルートでデータ取りたくて、Raspberry Pi 3 Model B+を購入しました。

自称C#erなのに.NET Coreは食わず嫌いでしたが、
ラズパイに.NET Framework入らないので、.NET Coreで開発しようとおもいます。
(Bルートのアプリはまだ開発中です。)

Raspbian(arm32)上で.NET Coreを動かす記事はいくつかありましたが、
リモートデバッグについては最近できるようになった？ようで、
日本語の情報がみつからなかったので自分のメモとして残します。

# 最近覚えたコト
## .NET Core 開発・実行
* .NET Core SDK＝Javaで言うJDK
* .NET Core Runtime＝Javaで言うJRE

## .NET Core アプリの展開
* フレームワークに依存する展開 (FDD)
    * .NET Core Runtimeがある前提のやつ
    * マルチプラットフォーム
    * `dotnet MyConsoleApp.dll`みたいに起動する
* 自己完結型の展開 (SCD)
    * exeつくるやつ(.NET Core Runtimeなしで動く）
    * プラットフォーム毎
    * `dotnet publish -r linux-arm`みたいな→[RID](https://docs.microsoft.com/ja-jp/dotnet/core/rid-catalog)

間違ってても許してください。やさしく教えてください。

# いろいろ前提条件 事前準備
* ハード：Raspberry Pi 3 Model B+
* OS：RASPBIAN STRETCH WITH DESKTOP
    * 開発PCから接続可能なLANの構成
    * SSHの有効化
    * sambaでファイル共有的なやつ

Linux/ラズパイ 素人なので、チュートリアル系記事読んで済ませました。
落としてきたイメージ書き込んで、wpa_supplicant.conf作って、sshファイル配置しました。

# 環境構築
## 開発側(Windows)
### Visual Studio Codeの場合
1. [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)いれます
1. [.NET Core 2.1 SDK](https://www.microsoft.com/net/download)いれます
1. [Visual Studio Code](https://code.visualstudio.com/)いれます
1. Visual Studio Codeの拡張機能いれます
    * [Japanese Language Pack for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja)
    * [C#](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp)
    * [NuGet Package Manager](https://marketplace.visualstudio.com/items?itemName=jmrog.vscode-nuget-package-manager)

### Visual Studio 2017(15.4以降)の場合
1. [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/latest.html)いれます
1. Visual Studio Installerで`.NET Core クロスプラットフォームの開発`ワークロードを有効にします。

## ラズパイ側
### .NET Core 2.1 Runtimeいれます
  
  "[このへん](https://www.microsoft.com/net/download/linux-package-manager/debian9/runtime-current)"とか"[このへん](https://docs.microsoft.com/en-us/dotnet/core/linux-prerequisites?tabs=netcore2x)"とか見ても、ARM64だしARM32の情報がなかなか見つからず。
  コピペでいけないとLinuxド素人にはつらい。
  探すこと１時間 ↓にたどりつきました。
   * [Setting up Raspian and .NET Core 2.0 on a Raspberry Pi](https://blogs.msdn.microsoft.com/david/2017/07/20/setting_up_raspian_and_dotnet_core_2_0_on_a_raspberry_pi/)
   * [Building, Running, and Testing .NET Core and ASP.NET Core 2.1 in Docker on a Raspberry Pi (ARM32)](https://www.hanselman.com/blog/BuildingRunningAndTestingNETCoreAndASPNETCore21InDockerOnARaspberryPiARM32.aspx)
  ＃はんせるまんのBlog Dockerだけかと思ったら最下部に普通のインストールパターンも書いてあった

  ランタイムは[ここ](https://github.com/dotnet/core/blob/master/release-notes/2.1/2.1.5/2.1.5.md)の`Runtime Binaries>Linux>ARM`からURLを拾ってきます。
  ＃`SDK Binaries>Linux>ARM`ってのもあるけど、Raspbian上でビルドできるんです…？
 
```bash:.NETCoreRuntime2.1.5
sudo apt-get -y install libunwind8 gettext
curl -sSL -o dotnet.tar.gz https://download.visualstudio.microsoft.com/download/pr/4d555219-1f04-47c6-90e5-8b3ff8989b9c/0798763e6e4b98a62846116f997d046e/dotnet-runtime-2.1.5-linux-arm.tar.gz
sudo mkdir -p /opt/dotnet && sudo tar zxf dotnet.tar.gz -C /opt/dotnet
sudo ln -s /opt/dotnet/dotnet /usr/local/bin
dotnet --list-runtimes
```

### vsdbgいれます
リモートデバッガ

```bash:
curl -sSL https://aka.ms/getvsdbgsh | bash /dev/stdin -r linux-arm -v latest -l ~/vsdbg
```

# プロジェクト作成～デバッグまで
## Visual Studio Codeの場合
1. コンソールプロジェクトを作成
  * 開発PCで `dotnet new console -n MyConsoleApp`する
  * VSCodeで`MyConsoleApp`フォルダを開く
  * C#拡張が`Required assets to build and debug are missing from 'MyConsoleApp'. Add them?`って聞いてくるので、`Yes!`
    * → `.vscode\launch.json`が作成されます。

1. ビルド
  * とりあえずF5して実行してみる。→`Hello World!`
  * 開発PCのVSCodeで、`dotnet publish`(FDDです)
1. デプロイ
  * SMB経由で、開発PCから`bin\Debug\netcoreapp2.1\publish`フォルダをラズパイにコピー

1. launch.jsonの追記
以下のように追記します。

```launch.json
{
    "name": ".NET Core Remote Launch - Framework Dependent (console)",
    "type": "coreclr",
    "request": "launch",
    "program": "/opt/dotnet/dotnet",
    "args": [
        "./MyConsoleApp.dll"
    ],
    "cwd": "~/publish（コピー先のパス）",
    "stopAtEntry": false,
    "console": "internalConsole",
    "pipeTransport": {
        "pipeCwd": "${workspaceRoot}",
        "pipeProgram": "c:\\Program Files\\PuTTY\\plink.exe",
        "pipeArgs": [
            "-pw",
            "パスワード",
            "pi@192.168.xxx.xxx"
        ],
        "debuggerPath": "~/vsdbg/vsdbg"
    }
}
```
実際は鍵でSSHしてます よ。

1. Debug
  * VSCodeのデバッグ(Ctrl+Shift+D)を開きます
  * 実行対象の構成 `NET Core Remote Launch - Framework Dependent (console)`を選択
  * F5!

```console
Starting: "c:\Program Files\PuTTY\plink.exe" -pw Password pi@192.168.xxx.xxx "~/vsdbg/vsdbg --interpreter=vscode"
-------------------------------------------------------------------
You may only use the Microsoft .NET Core Debugger (vsdbg) with
Visual Studio Code, Visual Studio or Visual Studio for Mac software
to help you develop and test your applications.
-------------------------------------------------------------------
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Private.CoreLib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Loaded '/home/pi/publish/MyConsoleApp.dll'. Symbols loaded.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Runtime.dll'. Module was built without symbols.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Console.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Threading.dll'. Module was built without symbols.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Runtime.Extensions.dll'. Module was built without symbols.
Hello World!
The program '[3550] dotnet' has exited with code 0 (0x0).
Error from pipe program 'plink.exe': Process is terminating due to StackOverflowException.

```
＃plink.exeがStackOverflowExceptionとなるのはなぜかよくわかってない

## Visual Studio 2017の場合
1. コンソールプロジェクトを作成
  * 開発PCで 新しいプロジェクト
  * `Visual C#`&gt;`.NET Core`&gt;`コンソールアプリ(.NET Core)`
  * とりあえずF5して実行してみる。→`Hello World!`
1. ビルド＆デプロイ
  * プロジェクトファイルを右クリックして発行
    * 構成がReleaseになってると思うので、Debugに変更
    * ターゲット(発行先)はSMB経由で、ラズパイ充てで

1. launch.jsonの作成
以下のように記述します。（保存先やファイル名は何でもいいです）

```launch.json
{
    "version": "0.2.0",
    "adapter": "C:\\Program Files\\PuTTY\\plink.exe",
    "adapterArgs": "-pw パスワード pi@192.168.xxx.xxx -batch -T ~/vsdbg/vsdbg --interpreter=vscode",
    "configurations": [
        {
            "name": ".NET Core Launch",
            "type": "coreclr",
            "cwd": "~/publish（コピー先のパス）",
            "program": "/opt/dotnet/dotnet",
            "args": [
                "./ConsoleApp1.dll"
            ],
            "request": "launch"
        }
    ]
}
```
実際は鍵でSSHしてます よ。

1. Debug
  * 以下のコマンドを、VSのコマンドウィンドウ(`Ctrl+W,A`)に打ち込みます

```console:デバッグ開始
DebugAdapterHost.Launch /LaunchJson:"launch.jsonの保存先(フルパス)"
```

```console:実行結果
-------------------------------------------------------------------
You may only use the Microsoft .NET Core Debugger (vsdbg) with
Visual Studio Code, Visual Studio or Visual Studio for Mac software
to help you develop and test your applications.
-------------------------------------------------------------------
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Private.CoreLib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Loaded '/home/pi/publish/ConsoleApp1.dll'. Symbols loaded.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Runtime.dll'. Module was built without symbols.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Console.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Threading.dll'. Module was built without symbols.
Loaded '/opt/dotnet/shared/Microsoft.NETCore.App/2.1.5/System.Runtime.Extensions.dll'. Module was built without symbols.
Hello World!
The program '[9933] dotnet' has exited with code 0 (0x0).
プログラム 'dotnet' はコード 0 (0x0) で終了しました。
```

# よくわかってない点
* VS2017でF5で開始できないものでしょうかね
* VSCodeとVS2017のlaunch.jsonの違い。アダプタホストが異なるから？
    * launch.jsonのドキュメントってないんですかね。

#参考にしたもの
* [Setting up Raspian and .NET Core 2.0 on a Raspberry Pi](https://blogs.msdn.microsoft.com/david/2017/07/20/setting_up_raspian_and_dotnet_core_2_0_on_a_raspberry_pi/)
* [Building, Running, and Testing .NET Core and ASP.NET Core 2.1 in Docker on a Raspberry Pi (ARM32)](https://www.hanselman.com/blog/BuildingRunningAndTestingNETCoreAndASPNETCore21InDockerOnARaspberryPiARM32.aspx)
* [Remote Debugging On Linux Arm](https://github.com/OmniSharp/omnisharp-vscode/wiki/Remote-Debugging-On-Linux-Arm)
* [Offroad Debugging of .NET Core on Linux OSX from Visual Studio](https://github.com/Microsoft/MIEngine/wiki/Offroad-Debugging-of-.NET-Core-on-Linux---OSX-from-Visual-Studio)
* [一番最初からRaspberry Piの無線LANをmicroSDで設定する方法](https://kokensha.xyz/raspberry-pi/how-to-set-up-wifi-into-sd-card-for-raspberry-pi/)

# おわりに
スマートメーターからデータ取りたくて、Wi-SUNドングル↓を買ったので、
これからシリアル通信と格闘です。
[Wi-SUNモジュール, Wi-SUN Route-B 専用 RL7023 Stick-D/IPS](https://www.tessera.co.jp/rl7023stick-d_ips.html)