新たな .NET ワークロード向けの開発ツール「AWS Toolkit for .NET Refactoring」が登場しました

2022.11.07

いわさです。

先日、AWS Toolkit シリーズに新しい仲間が登場しました。その名も「AWS Toolkit for .NET Refactoring」です。

AWS Toolkit なので IDE と AWS を統合し便利にデプロイ出来る類のもののよう見えますが今までの AWS Toolkit と全く違います。
このツールは .NET Framework ワークロードを .NET へ移行し AWS でホスティングさせるための Visual Studio 拡張です。

移行元の対象バージョンは .NET Framework 3.5 以降で、移行先バージョンは .NET Core 3.1、.NET 5、.NET 6 が対象となっています。
また、拡張を利用出来る Visual Studio のバージョンは 2019 と 2022 がサポートされています。

利用料金は無料です。
ただし、後述するテストのために ECS などへデプロイする場合、それらのリソース使用料金は発生します。

本日はこちらを使って ASP.NET MVC (.NET Framework 4.7.1) を ASP.NET Core (.NET 6) へ移行し、ECS でテスト実行するところまでをやってみました。

導入

Visual Studio の拡張機能の管理から「Toolkit for .NET Refactoring」で検索しダウンロードします。

Visual Studio 拡張機能なのでダウンロード環境後に Visual Studio を終了したタイミングでインストールが実行されます。

評価

まずは移行元の Web アプリケーションを用意し、「評価」を行います。
Visual Studio テンプレートから ASP.NET Web アプリケーションを選択し、Model-View-Controller で作成します。

はい、いつものやつです。

その後、拡張メニューから Toolkit for .NET Refactoring を選択し、「Get Started」を選択します。
ここで初期設定を行います。

AWS プロファイルやリージョンを選択出来ますが、あとから変更も出来ます。
リージョンはテストデプロイする ECS など一式のデプロイ先です。本日時点では us-east-2 と eu-west-2 のどちらかが選択出来ます。

初期設定するとダッシュボードが表示されます。
ここで「Start assesment」を選択すると評価を実行することが出来ます。

ターゲットフレームワークを選択します。

評価が完了すると、NuGet パッケージや .NET API の互換性の評価が完了します。
このあたりは後述の Porting Assistant for .NET と似ています。

移行

ここで移行、つまりプロジェクトを .NET Framework 4.7.1 から .NET 6 への変換を行ってみます。
もちろんプロジェクト形式だけでなくソースコードにも変更が発生します。
互換性がないものは置き換えられたりしますが一部は移行後に手動で調整が必要です。

こちらは変更前のソリューションエクスプローラーです。

こちらは変更後のソリューションエクスプローラーです。
ASP.NET Core に必要なモジュールが追加され、不要なモジュールが削除されているのがわかりますでしょうか。

ちなみにこのままだとビルドエラーになりましたので一部ソースコードの手動修正対応を行っています。
このあたりはマイクロソフト公式ドキュメントを参考にしながらトライアンドエラーする感じになりそうです。

例えば、@Scripts.Renderのいくつかを上記に従って置換しています。

ViewsShared_Layout.cshtml

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - マイ ASP.NET アプリケーション</title>
    <link rel="stylesheet"
          href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
          crossorigin="anonymous">
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse" title="その他のオプション">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("アプリケーション名", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("ホーム", "Index", "Home")</li>
                    <li>@Html.ActionLink("詳細", "About", "Home")</li>
                    <li>@Html.ActionLink("問い合わせ", "Contact", "Home")</li>
                </ul>
            </div>
        </div>
    </div>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - マイ ASP.NET アプリケーション</p>
        </footer>
    </div>

    <script src="https://code.jquery.com/jquery-3.3.1.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js"
            integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
    @RenderSection("scripts", required: false)
</body>
</html>

また、appsettings.json も変更しています。
今回は SSL 証明書の導入をしていないので HTTP のエンドポイントのみを定義しています。他の不要な情報もバサっと削りました。実際はワークロードにあわせての調整が必要です。

appsettings.json (変更前)

{
  "appsettings": {
    "webpages:Enabled": "false",
    "ClientValidationEnabled": "true",
    "UnobtrusiveJavaScriptEnabled": "true"
  },
  "ConnectionStrings": {
    "LocalSqlServer": "data source=.\\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://0.0.0.0:80"
      },
      "Https": {
        "Url": "https://0.0.0.0:443",
        "Certificate": {
          "Path": "<please provide path to cert>",
          "Password": "<certificate password>"
        }
      }
    }
  }
}

変更後は以下のような最低限な感じにしています。

appsettings.json (変更後)

{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://+:5000"
      }
    }
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

ASP.NET MVC の初期状態から移行したプロジェクトであれば、ここまででおそらくローカル実行は成功するようになるはずです。

テスト

次はテストです。
今回のこのテスト機能が今までの .NET 関係のマイグレーションツールと少し違うところでしょうか。
最低構成の ECS にコンテナ化してデプロイし、.NET + AWS へマイグレーションしたアプリケーションを評価する機能です。

ここは現状 ECS Fargate 固定のようなので、必要に応じて AWS Toolkit for Visual Studio を使って自前でデプロイしても良いと思います。
注意点として AWS Toolkit for .NET Refactoring のこのテスト機能はあくまでもテスト用のデプロイであって、運用環境へデプロイするためのものではないという点です。

Run test deployment から開始します。

...その前に、デプロイのために S3 バケットが必要になります。
このツールの対応リージョンが前述の 2 リージョンのみなので ECS のデプロイ対象リージョンへ S3 バケットが必要です。

また事前にデプロイ用の IAM ロールを作成しておきます。
公式ドキュメントにてデプロイ用の CloudFormation テンプレートが提供されています。

% aws s3 cp s3://aws.portingassistant.dotnet.download/ide.extension.role.creation/aws-refactoringtoolkit-iam-roles.yaml .
download: s3://aws.portingassistant.dotnet.download/ide.extension.role.creation/aws-refactoringtoolkit-iam-roles.yaml to ./aws-refactoringtoolkit-iam-roles.yaml
% aws cloudformation deploy --stack-name refactoringtoolkit --template-file aws-refactoringtoolkit-iam-roles.yaml --capabilities CAPABILITY_NAMED_IAM

Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - refactoringtoolkit

デプロイ前にビルドします。
どの環境でも良いのですが、私は発行機能を使って publish ディレクトリに Release ビルドモジュールを作成しました。

デプロイ画面ではプロファイル、パス、S3 バケット、ポートなどを指定します。
Advanced 設定としてコンテナのサイズなども指定出来ますがここでは割愛します。

注意点として、ロードバランサーや API Gateway などもデプロイされないので直接パブリック IP でアクセスしてテストするような形になります。
ASP.NET Core の場合だと待ち受けポート周りが面倒なので間違えないようにしましょう。テストなので私は Kestrel デフォルトを使いました。

デプロイがうまく成功すると以下のようにデプロイ詳細情報を確認出来ます。
そこでテスト用のエンドポイントも取得出来ます。

アクセスしてみると以下のように Web アプリケーションを表示することが出来ました。
CSS 周りが早速崩れているので修正が必要ですね。

日本語だとエラーになる

本日時点の注意点です。
日本語 Windows 環境だと ECS へのデプロイ時にエラーとなりました。日本語表記の日時フォーマットでエラーになっているので、これは前も Porting Assitant か App2Container で見た記憶があります。

このあたりのエラーが出たらおとなしく言語設定を変更します。

Porting Assitant for .NET との関係

.NET 使いの方でもしかすると Porting Assistant for .NET と被ってないか?と気になった方いらっしゃるかもしれません。
私も最初気になりました。

Porting Assistant for .NET は .NET Framework ワークロードを .NET へ移行するための AWS から提供されているツールです。

機能としては重複されているのですが、今回 AWS Toolkit for .NET Refactoring が登場したことで Porting Assistant for .NET に少し変更が入っています。

上記の v1.9.0 がその内容で、AWS プロファイルが不要になりました。
今までは AWS へデプロイしない場合でも Porting Assistant for .NET を利用することは出来ていました。ただし、AWS プロファイルの指定が必要でした。

これからは AWS プロファイルも不要になり、完全に AWS からは切り離されたツールとなりました。

さいごに

本日は「AWS Toolkit for .NET Refactoring」が登場したので使ってみました。

最少のデフォルトアプリでも少し修正が必要だったので、自動で全て変換してくれるものではないという点は意識しておきたいです。
とはいえ手動でプロジェクトファイル変更したりなどは大変などである程度で自動化してくれるのは楽ですね。
結局はトライアンドエラーが必要なのでそのあたりは覚悟が必要です。まずは評価だけでもしても良いかもしれないですね。

.NET Framework の .NET 化を検討しており、かつ AWS へ移行される場合は AWS Toolkit for .NET Refactoring という選択肢があることを覚えておきましょう。
また、移行先が AWS でない場合あるいはそもそも AWS アカウントも所有していないという場合は Porting Assistant for .NET も選択肢になります。