.NET Core とDockerで C#なウェブアプリケーションをLinuxで開発する

## 動機

正直Windows系の開発に興味がないのでC#, .NETにも興味は無いのですが、.NET Coreの登場によってLinux上で動くBetter JavaとしてのC#にはポテンシャルを感じます。
Microsoftも肩入れしているDocker上で動かすことができ、Amazon ECS上で運用できる可能性を考えると良い選択肢だと思われるのでここはひとつ冬休みの自由研究として学んでみたいと思います。

https://docs.microsoft.com/ja-jp/dotnet/articles/core/docker/building-net-docker-images
ここに書かれていることがほぼ全てですが、2016/12/27現在現在若干ハマりどころがあるので書いておきます。

また、各ステップごとで何が変更されるのかを下記のリポジトリに公開してあるので参考にしてください。
https://github.com/NewGyu/dotnet-core

## 環境の準備

筆者の環境は `Linux newgyu-XPS-13-9350 4.4.0-47-generic #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux` です。要するにUbuntu16.04です。
会社のMacでも試していますが、だいたい同じです。（きっと）

### yeoman をセットアップする

ゼロからプロジェクト構成を作っても良いのですが、MSのドキュメント通り[yeoman](http://yeoman.io/)のジェネレーターを使うのが手っ取り早いです。(ということでNode.jsの4以降が必要です)

```shell-session
$ npm install -g yo generator-aspnet generator-docker
```

### dotnetコマンドラインツールをセットアップする

公式チュートリアルではDockerを使っているので、ローカルに.NET Coreは要らんのかと思ったらそうでもなく、あとからVisual Studio Codeと連携させるために必要になります。

https://www.microsoft.com/net/download/core#/current

ここからインストールしましょう。

注意すべきはバージョン1.1にする必要があるということです。
というのも後述のジェネレーターでは1.1に依存したコードが吐かれるためです。

### Visual Studio CodeにC#機能拡張を入れる

https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp

## プロジェクトを作る

### aspnetジェネレーターで雛形を生成する

yeomanをインストールしたらベースのプロジェクトを生成します。

```shell-session
$ yo aspnet

     _-----_     ╭──────────────────────────╮
    |       |    │      Welcome to the      │
    |--(o)--|    │  marvellous ASP.NET Core │
   `---------´   │        generator!        │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |     
   __'.___.'__   
 ´   `  |° ´ Y ` 

? What type of application do you want to create? Web Application
? Which UI framework would you like to use? Bootstrap (3.3.6)
? What's the name of your ASP.NET application? WebApplication
   :
Your project is now created, you can use the following commands to get going
    cd "WebApplication"
    dotnet restore
    dotnet build (optional, build will also happen when it's run)
    dotnet ef database update (to create the SQLite database for the project)
    dotnet run
```

いろいろなテンプレートがあるのですが、ログイン機能などを有するWebApplicationを選びました。
生成されるコードはこちらになります。
https://github.com/NewGyu/dotnet-core/commit/03cd32a0d2dbc3cee4b997542c55195e6bd1dd0e

### dockerジェネレーターを使う

aspnetジェネレーターの時点で、

* 自身のローカルで動かせる
* Dockeで動かせる

という状態になっていますが、dockerジェネレーターによって、

* Visual Studio Code でデバッグできるようになる
* リリースビルドとデバッグビルドを使い分けられるようになる

という設定が追加されます。

```shell-session
$ yo docker

     _-----_     ╭──────────────────────────╮
    |       |    │   Welcome to the Docker  │
    |--(o)--|    │        generator!        │
   `---------´   │     Let's add Docker     │
    ( _´U`_ )    │  container magic to your │
    /___A___\   /│           app!           │
     |  ~  |     ╰──────────────────────────╯
   __'.___.'__   
 ´   `  |° ´ Y ` 

? What language is your project using? .NET Core
? Which version of .NET Core is your project using? rtm
? Does your project use a web server? Yes
? Which port is your app listening to? 5000
? What do you want to name your image? dotnet-core
? What do you want to name your service? dotnet-core
? What do you want to name your compose project? dotnetcore
? Overwrite .vscode/launch.json? overwrite
    force .vscode/launch.json
 conflict Dockerfile.debug
? Overwrite Dockerfile.debug? overwrite
    force Dockerfile.debug
 conflict Dockerfile
? Overwrite Dockerfile? overwrite
    force Dockerfile
identical docker-compose.debug.yml
identical docker-compose.yml
identical dockerTask.ps1
identical dockerTask.sh
? Overwrite .vscode/tasks.json? overwrite
    force .vscode/tasks.json
We noticed your project.json file didn't use portable .pdb files. We've fixed that for you.
Your project is now ready to run in a Docker container!
Run dockerTask.sh to build a Docker image and run your app in a container.
```

生成されるコードはこちらになります。
https://github.com/NewGyu/dotnet-core/commit/2c3877d89cbef7032a88a08f77451bf1644495d4

### Nugetリポジトリから依存ライブラリを取得

```shell-session
$ dotonet restore
```

## dockerジェネレータがいろいろ残念なので補正する

ここで、Visual Studio CodeでF5を押せばデバッグ実行…といきたいところですが、dockerジェネレータが吐くコードに現状に即していない箇所があるため修正を余儀なくされます。

### Dockerファイルの指すイメージのバージョン

https://github.com/NewGyu/dotnet-core/commit/945f75637e1254907d7355cdead531f5d20c635c

残念なことに、1.0系イメージを指しているので補正します。

### Dockerfile.debugのデバッガインストールの補正

https://github.com/NewGyu/dotnet-core/commit/341e2cc3467cdd88c156e55a095b13b2ccbfb2e5

[ClrDbgデバッガ](https://github.com/Microsoft/MIEngine)のインストールスクリプトが最近変わったのか`docker build`時にエラーが出ます。

ここまでで、

```shell-session
$ ./dockerTask.sh build debug
```

が、ようやく正常に完了するようになります。

### VSCodeの設定ファイルにlinux用の設定を加える

ここからは私のマシンがUbuntuだから必要なのだと懐います。
（Macでは必要ないかと思われます）

#### tasks.jsonにlinux用の設定を加える

https://github.com/NewGyu/dotnet-core/commit/0d84807ebb91dde4426152bf27000d07ab99cd03

dockerジェネレータが吐く設定はLinux用の設定が抜けていました。
MS love Linux言ってたのに残念な感じです。

#### launch.jsonのlaunchBrowser設定を消し去る

https://github.com/NewGyu/dotnet-core/commit/65436e5291e9695c9493cdd4d57f0b1afa6ecf41

これは自分のPC固有の問題かもしれません。
dockerジェネレータの吐く設定では、F5を押した時に

1. docker-composeでdockerイメージを起動
1. ローカルでdotnetコマンドを実行
2. docker exec でClrDbgを起動
3. ブラウザで http://localhost:5000 を起動

となっていましたが、ブラウザ起動後にデバッグ実行が失敗してしまいます。[これ](https://github.com/Microsoft/generator-docker/blob/master/generators/app/templates/dotnet/launch.json#L25-L27)を入れてみたのですが、改善されず諦めた形です。


ここまで来てようやくブレークポイントを設定してデバッグ実行ができるようになりました。

## プロダクション用のイメージを作る

```shell-session
$ ./dockerTask.sh build release
```

これは素直にできます。

----

## 所感

いろいろまだ発展途上な感じがします。

dotnetコマンドのインストーラのネーミングもわかりにくく、1.0系なのか1.1系なのかよくわからないネーミングです。

```shell-session
$ dotnet --info
.NET Command Line Tools (1.0.0-preview2-1-003177)

Product Information:
 Version:            1.0.0-preview2-1-003177
 Commit SHA-1 hash:  a2df9c2576
```

```shell-session
$ dotnet 

Microsoft .NET Core Shared Framework Host

  Version  : 1.1.0
  Build    : 928f77c4bc3f49d892459992fb6e1d5542cb5e86

```

また、チュートリアルにある`yo docker`(dockerジェネレータ)のメンテナンスが追いついてないように思えます。

とはいえ、冒頭にも申したとおりBetter JavaとしてのC#言語には魅力を多少感じますので、マイクロソフトとC#コミュニティの今後の発展に期待したいものです。