読者です 読者をやめる 読者になる 読者になる

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

既存の ASP.NET Web API アプリケーションを ASP.NET Core MVC 1.0 へマイグレーションしてみた

ASP.NET Core MVC

.NET Core 1.0 と ASP.NET Core 1.0 が RTM したので、とりあえず簡単なものからマイグレーションしてみました。ターゲットは無職になる前に作ったこれです。

この App Service Info は極めて単純な ASP.NET Web API アプリケーションなのと、既に Web Apps にデプロイして動かしていたので、そういう意味でも都合が良かったです。

マイグレーションの方法ですが、今回は C# のコードを新しく作成した Core MVC のプロジェクトにコピーすることにしました。プロジェクトの互換性なんてものは存在していないので、ソースレベルで対応します。

f:id:shiba-yan:20160628200748p:plain

ソースをコピーしてしまえば、後はコンパイルエラーを頑張って取り除いていく作業になります。とは言え Core MVC に関係する部分は割と簡単でしたが、.NET Core に関係する部分が手間がかかりました。

Core MVC 部分

今回のアプリケーションでは属性ベースのルーティングを使っていたので、コントローラの例を挙げると以下のような感じです。本当に普通の Web API を実装しているだけです。

[RoutePrefix("Api/Values")]
public class ValuesController : ApiController
{
    [Route]
    public IHttpActionResult Get()
    {
        return Ok();
    }
}

このコントローラを Core MVC 向けにコンパイルするためには、以下のような置き換えを行います。

  • ApiController を Controller に
  • RoutePrefix を Route に
  • 引数無しの Route を削除
  • IHttpActionResult を IActionResult に

これぐらいなら機械的に処理できそうな感じがしてきますね。実際に置き換えたのが以下のコードです。

[Route("Api/Values")]
public class ValuesController : Controller
{
    public IActionResult Get()
    {
        return Ok();
    }
}

あまり変わってないですが、ソースレベルの互換性は思ったより失われていない気がしてきます。実際には Request / Response を触っている場合は、もっとめんどくさくなるとは思います。

最後に Web API とは関係ない部分ですが、wwwroot 以下に index.html を置いていても、Web API ではミドルウェアが足りなくて 404 になっていたので、DefaultFiles と StaticFiles を追加しておきました。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    // デフォルトドキュメントと静的ファイルを有効にする
    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseMvc();
}

これで / で終わる URL にアクセスした時に、ちゃんと index.html が返されるようになりました。

.NET Core 部分

今回のアプリケーションでは、どっちかというと Core MVC よりも .NET Core に関係する部分のマイグレーションに手間がかかりました。具体的には以下のような部分です。

  • Environment.GetFolderPath が無い
  • Environment.OSVersion が無い
  • Assembly.Load で任意のパスから読めない

レジストリは使えるのに GetFolderPath が使えないのは、微妙に納得出来なかったですが、環境変数から取れる項目だったのでそっちに切り替えて今回は対応を行いました。

OSVersion に関しては System.Runtime.InteropServices に RuntimeInformation というクラスが追加されているので、OSDescription を使うとほぼ同じ情報が取れるようになってます。

// Microsoft Windows 6.2.9200
Console.WriteLine(RuntimeInformation.OSDescription)

あと、普段から ReSharper を使って開発していますが、現状では Roslyn の Code Fix を使った方が便利です。必要な NuGet パッケージを教えてくれるので便利です。

f:id:shiba-yan:20160628201552p:plain

結局 Assembly.Load はコードの見直しで不要になったので調べてないですが、AssemblyLoadContext を使えば任意のパスからアセンブリを読み込めるような気がします。

Web Apps へデプロイ

これまでは Visual Studio から Web Apps にデプロイしていましたが、GitHub でコードを公開しようと思ったのでソース管理からのデプロイに切り替えました。何もしなくてもビルドされて動作します。

f:id:shiba-yan:20160628174919p:plain

Process Explorer を見ると、ちゃんと dotnet コマンドが動いていることが確認できます。

f:id:shiba-yan:20160628174859p:plain

GitHub で今回 Core MVC 1.0 にマイグレーションしたコードを公開してあります。大したコード量ではないですが、多少でも参考になればと思います。