ASP.NET5 クロスプラットフォームでアプリケーションの動作環境を構築する

ASP.NET5 クロスプラットフォームでアプリケーションの動作環境を構築する
===

　実際に存在している、ASP.NET5アプリケーションを、Windows10 + Visual Studio 2015, Mac そしてUbuntuで動作させたので、そのTipsを記録しておきたい。今回のアプリケーションは、.NET Core 1.0.0-beta5を用いている。最新バージョンでないところが実際に現場で遭遇する状態に近いかもしれないので、その方法を共有したい。
　
　対象のアプリケーションは、Microsoftが公開しているPartsUnlimitedというアプリケーションである。[Microsoft / PartsUnlimited](https://github.com/Microsoft/PartsUnlimited)このリポジトリのdev/beta5ブランチで実施してみたい。
　
　ASP .NET5の情報はまだそんなに多くない。[ASP.NET Get Started](http://docs.asp.net/en/latest/getting-started/index.html)が英語リソースだがおすすめだ。
　
Windows10 + Visual Studio 2015
---

[Installing ASP.NET 5 On Windows](http://docs.asp.net/en/latest/getting-started/installing-on-windows.html)
Visual Studio 2015をインストールします。このアプリの[Get Started](https://github.com/Microsoft/PartsUnlimited/blob/dev/beta5/docs/GettingStarted.md)を読むと、Visual Studio 2015 RC対応です。ところが、すでにダウンロードできない。また、Microsoft SDK for .NET (VS 2015) - 2.6なので、これもRC用だ。

　この場面では、Visual Studio 2015をダウンロードして、それに対応した、Microsoft SDK for .NET (VS 2015) - 2.7をダウンロードすればよい。
　
　また、ASP.NET5関係の用語がよくわからない人はこの記事が秀逸。[「最新.NET技術がよく分からない」と感じる人のための用語整理](http://www.atmarkit.co.jp/ait/articles/1505/19/news016.html)

### 1. monoのランタイムを取得し.NET Coreのバージョンを変える

コマンドプロンプトをつかって、このdnvmコマンドをつかって、ランタイムを取得します。

```
# dnvm install 1.0.0-beta5
# dnvm list
Active Version              Runtime Arch OperatingSystem Alias
------ -------              ------- ---- --------------- -----
       1.0.0-beta5          mono         linux/darwin

# dnvm use 1.0.0-beta5
```

### 2. プロジェクトのチェックアウトと選択

その後、githubから、プロジェクトをTeam Explorerで複製して、分岐で、dev/beta5を指定して、ソリューションPartsUnlimited.slnを選択します。

### 3. プロジェクトのビルド

その後、プロジェクトを右クリック > プロパティ > アプリケーションのページのSolution DNX SDK version を 1.0.0-beta5に変更して、リビルドしておきます。エラーがでなければ問題ありません。その後、デバッグ実行をして、http://localhost:5001を選択するとページを見ることができます。

Mac
---
Macへのインストールも非常に簡単にできます。HomeBrewをつかって簡単にインストールできます。
[Installing ASP.NET 5 On MacOS X](http://docs.asp.net/en/latest/getting-started/installing-on-mac.html)

### 1. monoのインストール

わたしの環境だと、nodejs, npm, gruntなどはインストール済みであった。皆様もホームページの手順通りでインストール可能なので、インストールされたい。

```
$ brew install mono
$ curl -sSL https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.sh | sh && source ~/.dnx/dnvm/dnvm.sh
$ dnvm list
$ dnvm install 1.0.0-beta5
$ dnvm use 1.0.0-beta5
```

これは、手順ではありませんが、このリポジトリは現時点ではバグがあります。(25th Aug)下記のproject.jsonのカッコが一個おおいので、取り除いておきます。

```
vim /Users/ushio/Codes/devopshackathon/PartsUnlimited/src/PartsUnlimited.WebJobs.UpdateProductInventory/project.json
```

### 2. プロジェクトのビルド

プロジェクトのビルドは次のコマンドです。

```
$ dnu restore
```

### 3. Webサーバーの実行
次のとおり、kestrelサーバーを実行

```
$ cd PartsUnlimitedWebsite
$ dnx . kestrel
```

ブラウザで次のURLを開けるといい。
http://localhost:5001

Ubuntu
---
[Installing ASP.NET 5 On Linux](http://docs.asp.net/en/latest/getting-started/installing-on-linux.html)

Ubuntuは、手順にある通りではうまくいきません。実際に手順通り実施しても、NuGetのライブラリの取得がキャンセルされ、NuGetのライブラリが取得できない状況が発生します。そして、この現象は複数の理由で発生しますが、エラーメッセージだけではわかりませんので、発生原因をまとめて整理しています。

### 1. インストール手順の全体像

Ubuntuの手順はややこしいので、Vagrantで、アプリの実行まで出来るスクリプトを作成してみましたので、GitHubで共有しておきます。[TsuyoshiUshio / AspNetDevBeta05](https://github.com/TsuyoshiUshio/AspNetDevBeta05)

複数のファイルがあるが、Vagrantfileから各シェルファイルが実行される。最初に実行されるのは、parts_unlimited.sh経由で、common_ubuntu.shが実行される。これは、ubuntuの一般的な設定なので気にしなくても良い。

### 2. Vagrantならではのポイント

まず、VagrantでUbuntuを立ててそこに、このアプリの場合、ある程度メモリがある方が良さそうだ。Vagrantファイルで指定しておく

```
    master.vm.provider "virtualbox" do |vb|
    	vb.memory = "2048"
    end
```

また、普通にシェルを書くと、rootでシェルが実行されるので、次のオプションをつけて、シェルがvagrantユーザで実行されるようにしておく

```
 master.vm.provision "shell", path: "parts_unlimited.sh", privileged: false
```
これで、準備は完了です。

### 3. ASP.NET 5関連のインストール

実体は[common_asp_dotnet5.sh](https://github.com/TsuyoshiUshio/AspNetDevBeta05/blob/master/common_asp_dotnet5.sh)に記述しています。

最初の方の手順は、先に示した公式のインストール手順のままです。

このアプリの場合は、.NET Core 1.0.0-beta5を使うように設定をします。

```
dnvm install 1.0.0-beta5
dnvm use 1.0.0-beta5
```

次のポイントは次のパートです。これを全部入れておかないと、NuGetの取得でエラーになります。
次のようなエラーになります。こうなる原因は様々なので、次に対策をかいておきます。

```
==> master_01: Warning: DownloadPackageAsync: https://www.nuget.org/api/v2/package/Microsoft.AspNet.FileProviders.Abstractions/1.0.0-beta5
==> master_01:   A task was canceled.
==> master_01:   GET https://www.nuget.org/api/v2/package/Microsoft.AspNet.FileProviders.Abstractions/1.0.0-beta5
==> master_01: Warning: DownloadPackageAsync: https://www.nuget.org/api/v2/package/Microsoft.AspNet.Hosting.Abstractions/1.0.0-beta5
==> master_01:   A task was canceled.
==> master_01:   GET https://www.nuget.org/api/v2/package/Microsoft.AspNet.Hosting.Abstractions/1.0.0-beta5
==> master_01: Error: FindPackagesById: System.Diagnostics.Debug
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Globalization
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Diagnostics.Tools
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Linq.Expressions
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Linq
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Reflection
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Linq.Queryable
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Runtime
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Resources.ResourceManager
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Security.Claims
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Runtime.Extensions
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Text.Encoding
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Security.Principal
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.AspNet.Authorization
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: System.Threading.Tasks
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.AspNet.Mvc.ApiExplorer
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.AspNet.Cors
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.Framework.Caching.Memory
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.AspNet.Mvc.Razor
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.Framework.DependencyInjection
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.AspNet.Http.Extensions
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.AspNet.FileProviders.Abstractions
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.AspNet.Hosting.Abstractions
==> master_01:   A task was canceled.
==> master_01: Error: FindPackagesById: Microsoft.Framework.Logging.Abstractions
==> master_01:   A task was canceled.
==> master_01: ----------
==> master_01: System.Threading.Tasks.TaskCanceledException: A task was canceled.
```

#### 対策その１　ルート証明書

[Installing on Linux - missing certificate import steps #184](https://github.com/aspnet/Docs/issues/184)

原因の一つ目は、このアプリが使っているライブラリのCAルート証明書がないことに起因しています。本来は取得しないといけませんが、ca-certificates-monoというライブラリがいつの間にかできていますので、これを使うようにしましょう。

ちなみに、これらの手順はどう考えたかというと、DockerHubのMonoのDockerfileを参考にしている。[](https://github.com/mono/docker/blob/0d3556995aa47043059d60c42321e8ccaf173363/4.0.0/Dockerfile)

```
sudo apt-get update
sudo apt-get install -y mono-devel ca-certificates-mono fsharp mono-vbnc nuget \
	&& sudo rm -rf /var/lib/apt/lists/*
```

そのあとは、普通にnodejs, npm, gruntをインストールしています。

#### 対策その２ NuGet.Configの設定

これは公式にもある手順ですが、[Configuring the feed used by dnu to restore packages](https://github.com/aspnet/Home/wiki/Configuring-the-feed-used-by-dnu-to-restore-packages)このページにあるように、~/.config/NuGet/NuGet.configを書いておかないといけません。このアプリではdevelop中のライブラリを参照しています。

[parts_unlimited.sh](https://github.com/TsuyoshiUshio/AspNetDevBeta05/blob/master/parts_unlimited.sh)

このparts_unlimited.shは下記のようなNuGet.Configを、~/.config/NuGet/NuGet.Configに、保存しています。

```
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <add key="AspNetVNext" value="https://www.myget.org/F/aspnetvnext/api/v2/" />
    <add key="nuget.org" value="https://www.nuget.org/api/v2/" />
  </packageSources>
  <disabledPackageSources />
</configuration>
```

#### 対策その3 Monoのスレッドプールの設定

Monoのスレッドプールの設定をしない場合はこうなることがあるようです。わたしの場合は、Winマシンでは発生しませんでしたが、家のMacで同じくVagrantを使ったら発生しました。まったく同じコードなのに動かなかったので相当混乱しました。

`MONO_THREADS_PER_CPU`を2000に設定します。他の設定値も下記のスレにのっています。
parts_unlimited.shにも同様にコードをしています。

```
export MONO_THREADS_PER_CPU=2000
```


[Package restore on mono super slow and tons of requests end up being cancelled #1590](https://github.com/aspnet/dnx/issues/1590)

### アプリケーションの起動

基本的に、GitHubから、dev/beta5のブランチを取得し、Macの時と同じくの箇所で問題のあるファイルを修正しています。

```
#bad know-how for this repository. Until it will fix this.
mv /tmp/user-shell/inventory_project.json ~/PartsUnlimited/src/PartsUnlimited.WebJobs.UpdateProductInventory/project.json
```

ここまでくると、最後は同じです。

```
dnvm use 1.0.0-beta5
dnu restore
cd src/PartsUnlimitedWebsite
dnx . kestrel
```

実際にこのアプリケーションを動作させたい場合、VirtualBoxとvagrantをインストールしたのち

```
$ vagrant up
```

で、Ubuntu上に、各種設定を入れた上で、PartsUnlimitedアプリケーションが起動されます。

お疲れ様でした！