ASP.NET 5、.NET Core への移行作業をしてみた感想

この記事は、[ASP.NET Advent Calendar 2015](http://qiita.com/advent-calendar/2015/aspnet) の 10 日目 の記事です。

##はじめに

11月18日に、ASP.NET 5 と .NET Core の RC が公開されたので、[統計メモ帳](https://ecitizen.jp)という ASP.NET MVC 5 で作成・運用しているサイトの ASP.NET 5 への移行作業をしてみました。ここでは、その作業の感想を書きます。

作業をしてみて全般的な感想としては、ASP.NET 5、.NET Core ともに "Go Live" になっただけあって、Windows 環境だと特に問題なく動いています。一方で、MVC 5 からの変更が大きいので移行にはかなり手間が掛かるし、.NET Core の方は、ライブラリーの整備にもう少し時間がかかりそうだということは感じました。

#MVC 5 から MVC 6 への移行
今回の作業は大きく分けると、最初に MVC 5 から MVC 6 + .NET framework へ移行し、次に使用するフレームワークを .NET framework から .NET Core へ変更するという２つの作業に区分できます。MVC 5 から MVC 6 への移行については、[ASP.NET MVC Documentation](http://docs.asp.net/projects/mvc/en/latest/migration/migratingfrommvc5.html)を参考にして移行作業をしました。新規プロジェクトで、ASP.NET 5 の Web Application を作成して、そこに既存のコードを適当にコピーしていくという形になります。

###クライアント側のソフトはnpm+bower+gulpで管理
ASP.NET 5 では、下の図のようにファイル構成がかなり変更されていて、クライアント側は、VS ではなくて、npm、bower、gulp で管理し、公開時にはwwwrootのフォルダーが使われるようになります。VSのテンプレートではbowerが直接wwwrootのlibディレクトリーにインストールすつ設定になっていますが、ドキュメントの方は、bower_componentsフォルダーに保存し、gulpを使ってwwwrootのlibディレクトリーにコピーする設定になっています。クライアント側のライブラリーを編集しない場合はテンプレートのタイプが簡単だと思いますが、Bootstrap-sassを使いたいので、ドキュメントの方のタイプが便利だと思ってそちらにしました。npmとbowerによるパッケージの管理は、NuGetを使うよりは処理がスムーズになったと思います。なお、npmの方にも、Bootostrap、iQuery等が登録されているので、必ずしもbowerは使わなくてもいいようにも思います。gulp の使い方についてはよく分からないところがあるので、今後勉強していきたいと思っています。
![file.png](https://qiita-image-store.s3.amazonaws.com/0/103055/4f7457ff-30fd-e463-42ca-181988627c6e.png)


###サーバー側のソフトの移行
Controllers、Models 等にコードをコピーした時には、882エラーと大量のエラーが表示されどうなるのかと思いました。なお、後でよくみるとDNX4.5.1とDNX Core 5.0 でダブってエラーが表示される場合が多いので、実質的なエラーは882よりはかなり少なかったと思います。
![alt](http://~)
![error.png](https://qiita-image-store.s3.amazonaws.com/0/103055/a14cb5ec-902d-3e10-48ca-a3d3c550ff00.png)


電球マークをクリックするクイック操作で、修正のヒントがかなり的確に出てくるのでエラーの大部分はスムーズに消すことができました。ASP.NET 5 への自動変換ツールはまだないようですが、電球マークである程度の部分はカバーされてているように思いました。
![help.png](https://qiita-image-store.s3.amazonaws.com/0/103055/6db1f78c-4e70-ac01-7fa0-b67dbfc72147.png)

移行で手間がかかったのは、次のところでした。

+ 設定ファイル（Startup.cs、appsettings.json)
+ Dependency Injection
+ ライブラリーの変更で名前が変わっている
+ チャイルドアクションがなくなっていて、ViewComponentを使う
+ 単体テストでMSTestが使えない

その中で、一番苦労したのは、Dependency Injection（DI） の関係でした。今回のケースでDIして使う必要があったのは、EntityFramework、Identity、Logging、Cache の4つでした。

EntityFramework 7 については、以前と大きく変わっていて設定には苦労しました。データベースファーストで作っていたので、[ASP.NET 5 Application to Existing Database (Database First)](http://ef.readthedocs.org/en/latest/getting-started/aspnet5/existing-db.html)を参考にして設定をしました。
旧のコードは使えそうになかったので作成しなおしましたが、現時点では、コマンドプロンプトでコマンドを叩いて関連コードを作成する必要がありました。注には正式版ではもっと簡単に作成できるようになると書いてあり、まだ開発途中のようで、設定にも苦労しましたが、EntityFramework 6 よりシンプルで軽快になって使いやすくなっていると思います。

DIを使う場合に問題と感じたのは、Contorollers では、IActionResult Index([FromServices] EcitizenDbContext dbContext)というようにFromServicesを使って、Views では、@inject EcitizenDbContext dbContext というように@injectを先頭におくことで簡単にDIを使うことができるのですが、Models から DI を呼び出す適当な方法が見つかりませんでした。Models で呼び出しの階層が深い場合は普通にDIしていくとあまりにも手間がかかるので、取りあえずは、Startup.cs で app.ApplicationServices.GetService<EcitizenDbContext>() というような形で DbContext を取得して、static の public変数に保存してそれを各Classで使っています。自分が見落としているだけかも知れませんが、今回の作業で唯一気持ちの悪いところです。(追加)こういうルーティンはサービスにしろということのようです。

Logging については、NLog の設定方法がよく分からなかったのですが、[Logging のページ](https://github.com/aspnet/Logging)で、Providers に掲載されていたのが、[Serilog](http://serilog.net/) と [elmah.io](https://elmah.io/)だけだったので [Serilog](http://serilog.net/) を使うことにしました。Serilogでは、簡単ですが[説明](https://github.com/serilog/serilog-framework-logging)があったので動作させることはできました。

単体テストについては、MSTestは使えず [xUint.net](https://xunit.github.io/) を使う必要があるようですが、これについてはこれから作業をする予定です。

## .NET framework から .NET Core への移行
.NET framework ではなく .NET Core を使用すると、Mac、Linux で Mono なしで動作するようになりますが、.NET framework のライブラリーのすべてが .NET Core で対応いるわけでないので、対応していないライブラリーがある場合には、プログラムを書き直す必要がでてきます。今回のケースでは、次のライブラリーが .NET Core ではなくなっていたので、検討の必要がありました。

+ System.Net.Mail
+ System.Drawing
+ System.Runtime.Serialization.Formatters.Binary

System.Net.Mail については、Jeffrey Stedfast氏が[MailKit](https://github.com/jstedfast/MailKit)というOSSのメイルクライアントソフトを作成したことで、代用できる状況になりました。
https://github.com/dotnet/corefx/issues/1006

また、System.Drawing については、サーバー側で描画する場合の基本的なグラフィックス機能を提供するライブラリーですが、 こちらの方も当分はJames Jackson-South氏の作成した [ImageProcessor](https://github.com/JimBobSquarePants/ImageProcessor/tree/Core)で代用することになりそうです。
http://www.hanselman.com/blog/RFCServersideImageAndGraphicsProcessingWithNETCoreAndASPNET5.aspx

こういうことは今までなかったことだと思うので、.NET Core がオープンソースになって公開されたことのメリットが出てきていると思いました。

Logging のソフトでは、Serilog が、.NET Core に対応していました。ログのローリングができない等対応はまだ限定的ですが、ログのファイル書き出しは可能です。なお、NLogの方は、.NET Core 対応の開発を始めたばかりのようです。

## コンソールアプリケーションの移行
[統計メモ帳](https://ecitizen.jp)では、Webアプリケーション以外に、定期的にデータを取得してくるためのコンソールアプリケーションを動かしています。
そのコンソールアプリケーションの .NET Core への移行については、まだ作業にかかれていませんが、[.NET Core](http://dotnet.github.io/getting-started/)のページで shell をインストールして、以下のように dotnet コマンドを叩いていくとネイティブのコンソールアプリケーションが作成できるという [.NET CLI](https://github.com/dotnet/cli)が公開されました。

```dotnet new
dotnet restore
dotnet run
dotnet compile --native
```

Ubuntu でテストしてみると、実際に実行ファイルができているし動作もします。
![native.png](https://qiita-image-store.s3.amazonaws.com/0/103055/2c8a8a8a-6a89-d95a-4a67-b848a4181504.png)

コンソールアプリケーションは実際に動作している時間は限られているので、ネイティブのアプリがLinuxで動作するのであれば、Amazon Lambda が使える可能性が高く、それだとコードが動いている時間だけの課金なので、非常に安価にコンソールアプリケーションを別サーバーにすることが可能です。そういうことで、コンソールアプリケーションのネイティブ化には大いに期待しています。

##最後に
移行作業に約1週間をかけていますが、取りあえず動くところまではきていますが、まだ終わっていません。自分の能力の問題もあるのですが、ASP.NET 5 は変更点が多いので、移行作業に手間がかかるというのは現実だと思います。作業は結構楽しくやれています。Microsoft の関係で面白いなと思うのは本当に久しぶりのことだと思います。

公式ドキュメントについては、未完成の部分が多いですが、移行作業は、公式ドキュメントと Stack Overflow を見ることでほぼできているので、従来よりはかなりわかりやすくなっていると思います。