モノリシックなASP.​NETアプリケーションのモダナイゼーションを支援する AWS Microservice Extractor for .​NETを使ってみた #reinvent

2021.12.02

いわさです。

AWS re:Invent 2021にてAWS Migration Hub Refactor Spacesが発表されました。

上記サービスはインフラ環境を整備することでリファクタリングを支援してくれますが、それとは別で.NETアプリケーションをモダナイゼーションするためのツールも同時に発表されました。
それがこちらの AWS Microservice Extractor for .NETです。

Introducing AWS Microservice Extractor for .NET

本日はこちらのツールの使い勝手などを簡単なASP.NETソリューションを使って確認してみましたので、ご紹介します。

先にまとめ

このツールは大規模なASP.NET Webアプリケーションをモノリスからマイクロサービスへと移行を「支援」してくれるツールです。
Windows環境へダウンロードして使うスタンドアロンツールで利用料金は無料です。

このツールが何をしてくれるのか、開発者が何をする必要があるのかをざっと並べます。

  • ツールはASP.NETのソリューションを依存関係など含め解析。.NET4.7+のASP.NET Webがターゲットで解析にはMSBuild必須。
  • ツールは解析後、依存関係や名前空間などを考慮のうえグラフ形式で視覚化してくれる。開発者は視覚化された情報を使ってラベリングや独立したサービスの抽出作業を行う
  • ツールは抽出したサービスを既存コードから分離させ、依存コードをリファクタリングする(すごい)
  • 開発者はリファクタリングされたソースコードをベースに追加の修正を行い、手動でインフラへデプロイする。手動なのでデプロイ先はAWSである縛りはない。

ためしてみた

ダウンロード・インストール

ツール実行のためのオペレーティングシステムは以下とされています。

  • Windows7+
  • Windows Server 2016+

以下からダウンロードし、インストールしてください。

.NET Microservices – AWS Microservice Extractor for .NET – Amazon Web Services

起動・セットアップ

ツールの初回起動時にはAWS Region、AWS CLIプロファイル、MSBuildパス、出力ディレクトリなどを設定していきます。

MSBuildはVisual Studioをインストールするか、他には.NET SDK単体でのインストールでも入手出来ます。

プロファイルは以下の権限が必要です。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Resource": [
        "*"
      ],
      "Action": [
        "serviceextract:GetConfig"
      ]
    },
    {
      "Sid": "SectionForMetricsService",
      "Effect": "Allow",
      "Action": "execute-api:invoke",
      "Resource": [
        "arn:aws:execute-api:us-east-1:*:*/prod/POST/put-metric-data",
        "arn:aws:execute-api:us-east-1:*:*/prod/POST/put-log-data"
      ]
    }
  ]
}

何らかのデータをどこかのアカウントのAPI Gatewayに送信しそうなポリシーですが、Microservice Extractorはソースコードなどの情報は収集しないとされています。
この点気になる方多いと思いますが、何を収集するのか・無効化出来るのかなど詳細は以下をご確認ください。

AWS Microservice Extractor for .NET security - AWS Microservice Extractor for .NET

アプリケーションのオンボード

このツールはASP.NET Webアプリケーションをターゲットにしています。
アプリケーションの視覚化は.NET Framework4.0以上であれば利用可能で、さらにその後のグループ化したサービスの抽出まで行う場合は.NET Framework4.7以上である必要があります。

今回はASP.NET MVC(.NET Framework 4.7.1)で、デフォルトのHomeControllerを少しだけ修正したものを使ってみます。

HomeController.cs

using System.Web.Mvc;

namespace hoge_extractor.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            //ViewBag.Message = "Your contact page.";
            ViewBag.Message = new ContactRepo().GetContact();

            return View();
        }
    }

    public class ContactRepo
    {
        public string GetContact() => "hoge contact";
    }
}

アプリケーションのオンボードは、ASP.NET Webアプリケーションのソリューションファイル(.sln)を指定するだけです。
IIS配下などに存在している必要もありません。

なお、Analyze .NET Core Portabilityのオプションでは.NET Frameworkから.NET Coreへの移行性を評価出来ます。
仕組みとしては以前ご紹介させて頂いたPorting Assistant for .NETを使う形です。(事前にインストールが必要)

解析が終わったら、オンボードされたアプリケーションの詳細情報を確認します。

視覚化

Visualizationタブを開くとクラスの依存関係が視覚化されています。
開発者はこの情報を元に、何を抽出するべきかなどリファクタリングの方向性を検討します。

独立したサービスをグループとして定義していきます。
このように視覚化された情報をもとにすることは出来ますが、どのサービスを独立させるべきなのかは開発者が判断を行う必要がある点を覚えておいてください。

抽出

作成したグループを独立したサービスとして抽出してみます。
グループを選択しExtract group as serviceを選択してください。

オプションとして抽出されたサービスへのメソッド呼び出しの方法を選択することが出来ます。
抽出前はインスタンスメソッドを呼び出していましたが、User remote method invocationsに変更してみたいと思います。

抽出後、初期設定で指定したディレクトリに2つのソリューションが出力されました。
ソースコードを確認してみましょう。

抽出されたサービスは以下のように新たにコントローラーが定義され、WebAPIとして呼び出し可能な状態となっていました。

ContactRepoController.cs

using System;
using System.Web.Http;
using Newtonsoft.Json;
using System.Web.Http.Description;
using System.Web.Mvc;
using hoge_extractor.Controllers;

namespace hoge_extractor.Controllers
{
    [RoutePrefix ( "api/ContactRepo" )]
    public class ContactRepoController : ApiController
    {
        [Route("GetContact_e3b0c442")]
        [ResponseType(typeof(string))]
        [HttpPost]
        public IHttpActionResult GetContact_e3b0c442Wrapper(dynamic endpointContainer)
        {
            try
            {
                dynamic ctorContainer = EndpointParamStore.GetConstructorContainer(endpointContainer);
                dynamic methodContainer = EndpointParamStore.GetMethodContainer(endpointContainer);
                ContactRepo myInstance = null;
                string ctorParamHash = EndpointParamStore.GetConstructorParamHash(ctorContainer);
                // Initialize the right constructor
                if (ctorParamHash.Equals("e3b0c442"))
                {
                    myInstance = new ContactRepo();
                }

                // Retrieve Method parameters
                return Ok(myInstance.GetContact());
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                return InternalServerError(e);
            }
        }
    }
}

一方、呼び出し側は以下のように、リモート呼び出しに変更されていました。すごい。
さらに抽象化レイヤーも自動生成されていました。

HomeController.cs

using System.Web.Mvc;
using hoge_extractor.EndpointAdapter;

namespace hoge_extractor.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";
            return View();
        }

        public ActionResult Contact()
        {
            //ViewBag.Message = "Your contact page.";
            ViewBag.Message = ContactRepoEndpointFactory.GetEndpointAdapter().GetContact();
            return View();
        }
    }

    public class ContactRepo
    {
        public string GetContact() => "hoge contact";
    }
}

なお、コピーと修正をする形で抽出されるので、不要になったクラスは手動で整理する必要があります。

さいごに

本日は AWS Microservice Extractor for .NET をご紹介しました。
本ツールはAWSに関わらず全ての.NETユーザーが利用可能です。
ASP.NETアプリケーションの改善を検討している方は、利用料金も無料なので、是非お試しください。