Linuxで.NETの開発をする

(An [English version of this article](https://www.linkedin.com/pulse/building-net-development-environment-linux-hideki-saito/) is also available.)

筆者は複数のマシンを持っていますが、そのうちの一台はLinuxが入っています。デスクトップ機である関係上、これを開発に使うことも多いのですが、その環境に関して紹介していきたいと思います。

# 何ができるのか？
[.NET Core](https://dotnet.microsoft.com/)は複数のプラットフォーム対応がなされているため、開発に関してもほとんどWindowsと同じようなことができます。

## 可能なこと
筆者が可能であると確認しているのは以下のとおりです。

* コマンドラインツールの開発とデバッグ。
* ウェブアプリケーション（[ASP.NET](https://dotnet.microsoft.com/apps/aspnet)、[Blazor](https://blazor.net)など）の開発とデバッグ。
* [PowerShell](https://microsoft.com/PowerShell) （旧PowerShell Core）バイナリモジュールの開発とデバッグ（プロセスにアタッチしてのデバッグ）。
* .NET Core Tools（[Entity Framework](https://docs.microsoft.com/en-us/aspnet/entity-framework)、[ML.NET](https://dotnet.microsoft.com/apps/machinelearning-ai/ml-dotnet)など）の取得と実行。
* [Unity](https://unity.com/)を使用した開発。（以前はWindows、Macのみでしたが、Beta期間を経て、正式に利用できるようになりました。）

## 不可能（または困難）なこと

* WinFormやWPFなどのGUIアプリケーションの開発。
* .NET Frameworkをターゲットにする開発。
* Xamarinを使用した開発。（サポートされていないものの、厳密にはできないことはないようです。例えば、xamarin-androidは[Jenkins](https://jenkins.mono-project.com/view/Xamarin.Android/job/xamarin-android-linux/lastSuccessfulBuild/Azure/)から取り出してくることで、使用できるようです。）

# 環境の作り方

## .NET Core
.NET Coreはほとんどのメジャーなディストリビューションで使用することができ、また各種パッケージも提供されていますが、おすすめしたいのは、[シェルスクリプト](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-install-script)を使用したインストールです。

シェルスクリプト経由のインストールを行うことで、複数のバージョンの.NET Coreランタイムやライブラリのインストールが容易になります。

例えば、LTS版をインストールする場合は、以下のような形です。

```shell
./dotnet-install.sh --channel LTS
```

尚、追加でインストールが必要なライブラリが必要になるかもしれません。一般的にあまり通常では入っていないと思われるものはlibicuです。

インストール先はユーザーが書き込める場所でなくとも構いません。追加のテンプレートやツールなどはそれぞれのユーザーの管理下に置かれます。

## 開発環境
### Visual Studio Code
無料で開発環境を揃えたいのであれば、以下のような組み合わせがおすすめになります。

- [Visual Studio Code](https://code.visualstudio.com/)
- [Visual Studio Code用C#拡張](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp)

上記で、開発が開始できる環境にすることができます。

### JetBrains Rider
開発環境にお金を出してもいい、という方は、[JetBrains Rider](https://www.jetbrains.com/ja-jp/rider/)を検討するもの一つの選択肢になります。JetBrains社はVisual Studio用のリファクタリングプラグインである[ReSharper](https://www.jetbrains.com/ja-jp/resharper/)を開発している会社でもあり、高度なコーディング支援が提供されるため、快適に開発することができます。

RiderはRider単体、RiderとReSharper同梱版、全IDE製品を含んだAll Products Packが存在しています。詳しくは[購入ページ](https://www.jetbrains.com/ja-jp/resharper/buy/)を参照して下さい。（筆者は他の言語のものも使用することがあるため、All Products Packを個人的に契約しています。）尚、Riderに限らず、JetBrains社のほとんどのIDEはWindowsなどの他の環境でも使用できるため、複数のOSで同じIDEを使用できるという点においても重宝しています。

また、[NuGet](https://www.nuget.org/)パッケージ管理などもグラフィカルにできるため、C#を行う機会が多い、という方におすすめです。

### その他
尚、[OmniSharp](http://www.omnisharp.net/)（上記の拡張でも使用）を用いることで、[Language Server Protocol](https://langserver.org/)に対応したお好みのエディタで開発することも可能です。この方法はエディタによって変わってくるのでここでは割愛します。

# 早速試してみる

## プロジェクト作成

環境を揃えると開発を開始することができます。

プロジェクトを作成するのにはdotnetコマンドを使用します。

```shell
dotnet new console -o myapp
```

以下の用に、引数を入れずに実行すると使用できるテンプレートが表示されます。

```shell
dotnet new
```
```
Usage: new [options]

Options:
  -h, --help          Displays help for this command.
  -l, --list          Lists templates containing the specified name. If no name is specified, lists all templates.
  -n, --name          The name for the output being created. If no name is specified, the name of the current directory is used.
  -o, --output        Location to place the generated output.
  -i, --install       Installs a source or a template pack.
  -u, --uninstall     Uninstalls a source or a template pack.
  --nuget-source      Specifies a NuGet source to use during install.
  --type              Filters templates based on available types. Predefined values are "project", "item" or "other".
  --dry-run           Displays a summary of what would happen if the given command line were run if it would result in a template creation.
  --force             Forces content to be generated even if it would change existing files.
  -lang, --language   Filters templates based on language and specifies the language of the template to create.
  --update-check      Check the currently installed template packs for updates.
  --update-apply      Check the currently installed template packs for update, and install the updates.


Templates                                         Short Name               Language          Tags                                 
----------------------------------------------------------------------------------------------------------------------------------
Console Application                               console                  [C#], F#, VB      Common/Console                       
Class library                                     classlib                 [C#], F#, VB      Common/Library                       
WPF Application                                   wpf                      [C#]              Common/WPF                           
WPF Class library                                 wpflib                   [C#]              Common/WPF                           
WPF Custom Control Library                        wpfcustomcontrollib      [C#]              Common/WPF                           
WPF User Control Library                          wpfusercontrollib        [C#]              Common/WPF                           
Windows Forms (WinForms) Application              winforms                 [C#]              Common/WinForms                      
Windows Forms (WinForms) Class library            winformslib              [C#]              Common/WinForms                      
Worker Service                                    worker                   [C#]              Common/Worker/Web                    
Unit Test Project                                 mstest                   [C#], F#, VB      Test/MSTest                          
NUnit 3 Test Project                              nunit                    [C#], F#, VB      Test/NUnit                           
NUnit 3 Test Item                                 nunit-test               [C#], F#, VB      Test/NUnit                           
xUnit Test Project                                xunit                    [C#], F#, VB      Test/xUnit                           
Razor Component                                   razorcomponent           [C#]              Web/ASP.NET                          
Razor Page                                        page                     [C#]              Web/ASP.NET                          
MVC ViewImports                                   viewimports              [C#]              Web/ASP.NET                          
MVC ViewStart                                     viewstart                [C#]              Web/ASP.NET                          
Blazor Server App                                 blazorserver             [C#]              Web/Blazor                           
Blazor WebAssembly App                            blazorwasm               [C#]              Web/Blazor/WebAssembly               
ASP.NET Core Empty                                web                      [C#], F#          Web/Empty                            
ASP.NET Core Web App (Model-View-Controller)      mvc                      [C#], F#          Web/MVC                              
ASP.NET Core Web App                              webapp                   [C#]              Web/MVC/Razor Pages                  
ASP.NET Core with Angular                         angular                  [C#]              Web/MVC/SPA                          
ASP.NET Core with React.js                        react                    [C#]              Web/MVC/SPA                          
ASP.NET Core with React.js and Redux              reactredux               [C#]              Web/MVC/SPA                          
Razor Class Library                               razorclasslib            [C#]              Web/Razor/Library/Razor Class Library
ASP.NET Core Web API                              webapi                   [C#], F#          Web/WebAPI                           
ASP.NET Core gRPC Service                         grpc                     [C#]              Web/gRPC                             
dotnet gitignore file                             gitignore                                  Config                               
global.json file                                  globaljson                                 Config                               
NuGet Config                                      nugetconfig                                Config                               
Dotnet local tool manifest file                   tool-manifest                              Config                               
Web Config                                        webconfig                                  Config                               
Solution File                                     sln                                        Solution                             
Protocol Buffer File                              proto                                      Web/gRPC      
```

足りないテンプレートに関してはオンライン取得して、インストールすることができます。

```shell
dotnet install hoge
```

これで、myappディレクトリ内にコンソールアプリケーションのボイラープレートコードが生成されますので、エディタを開き、このまま開発を開始できます。（Visual Studio Codeは初回起動にはC#プラグインの必要コンポーネントとダウンロードが行われるため、ネット環境が必要であり、また少し次回がかかるかもしれません。）

Riderを使用している場合は、専用ダイアログからプロジェクトを作成できます。

![riderproject.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80859/3bbe73f8-4a48-0665-6888-35b7085eeaa1.png)

対応していないテンプレートもあるので、その場合はコマンドラインからプロジェクトを作成する形になります。

### .NET Coreツール
dotnetコマンドを使用することで、プロジェクトの作成や操作を行う他[.NET Coreツール](https://docs.microsoft.com/ja-jp/dotnet/core/tools/global-tools)という形で各種のツールもインストールすることができます。

例えば、PowerShellも.NETの一部としてインストールすることができ、その場合は以下のようになります。

```shell
dotnet tool install -g powershell
```

これは他にもML.NETツールなどをインストールしたい場合も同様です。

```shell
dotnet tool install -g mlnet
```

## デバッグ

Visual Studio Codeでデバッグすることも可能で、通常のVisual Studioのような使用感で行うことができます。
![vscode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80859/d9f8aa27-a44b-267a-009b-af9bc84efda5.png)

ただし、設定は<code>launch.json</code>などを書き換えていく必要があるため、少し慣れが必要かもしれません。以下、その例を示します。

```json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": ".NET Core Launch (console)",
            "type": "coreclr",
            "request": "launch",
            "WARNING01": "*********************************************************************************",
            "WARNING02": "The C# extension was unable to automatically decode projects in the current",
            "WARNING03": "workspace to create a runnable launch.json file. A template launch.json file has",
            "WARNING04": "been created as a placeholder.",
            "WARNING05": "",
            "WARNING06": "If OmniSharp is currently unable to load your project, you can attempt to resolve",
            "WARNING07": "this by restoring any missing project dependencies (example: run 'dotnet restore')",
            "WARNING08": "and by fixing any reported errors from building the projects in your workspace.",
            "WARNING09": "If this allows OmniSharp to now load your project then --",
            "WARNING10": "  * Delete this file",
            "WARNING11": "  * Open the Visual Studio Code command palette (View->Command Palette)",
            "WARNING12": "  * run the command: '.NET: Generate Assets for Build and Debug'.",
            "WARNING13": "",
            "WARNING14": "If your project requires a more complex launch configuration, you may wish to delete",
            "WARNING15": "this configuration and pick a different template using the 'Add Configuration...'",
            "WARNING16": "button at the bottom of this file.",
            "WARNING17": "*********************************************************************************",
            "preLaunchTask": "build",
            "program": "${workspaceFolder}/bin/Debug/netcoreapp3.1/myapp.dll",
            "args": [],
            "cwd": "${workspaceFolder}",
            "console": "internalConsole",
            "stopAtEntry": false
        },
        {
            "name": ".NET Core Attach",
            "type": "coreclr",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}
```

設定ファイル自体は自動生成する機能がありますが、プラットフォーム名（<code>netcoreapp3.1</code>）やアプリケーション名（<code>myapp.dll</code>）などは各自設定する必要があります。

Riderを使用する場合は、設定に関しては自動的に行ってくれる部分も多いのでかなり楽です。
![rider.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/80859/7dd84c4f-215d-07f4-6960-8fd8669ba6ee.png)

# 最後に

.NET Core登場以前はMonoなどがあったものの、やはり.NETはWindowsの環境という性格が強かったのですが、.NET Core登場以後はツール周りも含めて、Linux環境下でも遜色ない開発ができるようになってきました。

特にデプロイ先がLinuxである場合など、Linuxで開発できると便利、という場面もあるかもしれません。そのような場合に、Linuxでも開発環境が作れるというのは大きな利点だと思います。