.NET アップグレード アシスタントを使って .NET 6に移行してみた

普段のお仕事に役立つ普遍的なプログラミングTIPSや、業界で注目度が高い最新情報をお届けする「編集部ピックアップ」。
今回はマイクロソフト社が提供しているツール「 .NET アップグレード アシスタント」を使用して、 .NET Frameworkで作成したWindows Formsアプリを .NET 6に移行する方法を解説します。

.NET アップグレード アシスタントとは

.NET アップグレード アシスタントは、 .NET Frameworkで作成されたWindows Formsアプリを .NET 6にアップグレードするためのコマンドラインツールです。

.NETの登場により .NET Frameworkは4.8を最終バージョンとし、新規機能の追加も行われません。そんな中、 .NET Frameworkで作成されたアプリケーションを .NETに移行したいけど移行方法がわからない、という方も沢山いらっしゃるかと思います。

今回の記事では、 .NET アップグレード アシスタントを使って .NET Frameworkで作成したWindows Formsアプリを .NET 6にアップグレードする方法について解説します。

.NET アップグレード アシスタントの使い方

.NET アップグレード アシスタントを使った .NET 6への移行方法として、詳しい手順がマイクロソフト社の以下のページに公開されています。

今回はこちらの手順をもとに、 .NET 6への移行を試してみたいと思います。サンプルプログラムは、手順にあるGitHubで公開されているものを使用して行います。

.NET 6への移行する前に、サンプルが .NET Frameworkで作成されていることを確認します。

移行元のプロジェクト

.NET アップグレード アシスタントのインストール

.NET アップグレード アシスタントのインストール方法は前述の公式ページに公開されています。

前提条件

.NET アップグレード アシスタントの実行には以下の条件がありますので予め環境を用意しておいてください。

  • Windows オペレーティング システム
  • .NET 6 SDK
  • Visual Studio 2022 17.0 以降

コマンドプロンプトを展開し、次のコマンドを実行してインストールを行います。

dotnet tool install -g upgrade-assistant
.NET アップグレード アシスタントのインストール

また、 .NET アップグレード アシスタントは現在プレリリースとして公開されており、頻繁に更新が行われています。次のコマンドを実行してツールの更新を行うことができます。

dotnet tool update -g upgrade-assistant
.NET アップグレード アシスタントの更新

移行対象のアプリを分析する

.NET アップグレード アシスタント ツールでは、 .NET 6への移行を行うための分析モードが備わっており、移行する前にどのような変更が必要になるかに関する分析情報を確認できます。

コマンドプロンプトを展開し、ターゲットプロジェクトもしくはソリューションが配置されているフォルダに移動し、次のコマンドを実行することで確認することができます。

upgrade-assistant analyze MatchingGame.sln

今回使用するサンプルプログラムに対して分析モードを実行すると次の出力結果がでました。

分析結果

注目したい内容として、プロジェクトが「TFM(ターゲットフレームワークモニカー)」として「net6.0-windows」を対象としていることを示しています。これはソリューションによって参照されるプロジェクトがWindows Formsプロジェクトであるためであり、一部のWindows固有のライブラリを使用しない場合はコンソールアプリケーションがTFM net6.0への直接アップグレードを推奨します。

エラーや警告が表示された場合は、内容を確認して修正してください。

※今回は以下の警告が表示されていますが、HighDpiModeとしてSystemAwareを使用することを推奨しており移行には影響はないため無視します。

[**:**:** WRN] HighDpiMode needs to set in Main() instead of app.config or app.manifest - Application.SetHighDpiMode(HighDpiMode.<setting>). It is recommended to use SystemAware as the HighDpiMode option for better results.

upgrade-assistantの実行

コマンドプロンプトを展開し、ターゲットプロジェクトもしくはソリューションが配置されているフォルダに移動し、以下のコマンドを実行することでプロジェクトを移行する順序に関する提案が表示されます。

upgrade-assistant upgrade MatchingGame.sln

コマンドを実行すると、行われるステップの一覧が表示されますので、対応するコマンドを実行することで移行を行うことができます。ステップによって実行できるコマンドが異なりますが、大きく分けて以下のコマンドを実行できます。基本的には、「1」の「Apply next step」を次々実行していくことになります。

  1. Apply next step(コマンドを実行し、次のステップを表示する)
  2. Skip next step(コマンドを実行せず、次のステップを表示する)
  3. See more step details(ステップの詳細を確認する)
  4. Select different project(プロジェクトを変更する)
  5. Configure logging(ログ設定を変更する)
  6. Exit(移行を停止して終了する)

サンプルプログラムを移行する最初のステップとして、ソリューション内でのエントリポイントとするプロジェクトを選択します。

Upgrade Steps

1. [Next step] Select an entrypoint
2. Select project to upgrade

「1」を選択しコマンドを実行すると、次の結果が表示されます。

[**:**:** INF] Applying upgrade step Select an entrypoint
Please select the project you run. We will then analyze the dependencies and identify the recommended order to upgrade projects.
   1. MatchingGame
   2. MatchingGame.Logic

メインとなるWindows Formsアプリ(MatchingGame)とライブラリプロジェクト(MatchingGame.Logic)が表示されるため、エントリポイントとして「1」の「MatchingGame」プロジェクトを選択します。

次のステップとして、移行を行うプロジェクトを選択します。移行を行う順番として、メインプロジェクトが依存しているライブラリプロジェクト(MatchingGame.Logic)を最初に移行する必要があると判断しています。基本的には推奨される移行順序に従って実行することをお勧めします。

[**:**:** INF] Applying upgrade step Select project to upgrade
Here is the recommended order to upgrade. Select enter to follow this list, or input the project you want to start with. 
   1. MatchingGame.Logic
   2. MatchingGame

※ MatchingGame.Logicは単純なプロジェクトであり、移行後に問題は発生しないため、手順は省略します。以下は2番目に移行を行う「MatchingGame」の例を紹介します。

プロジェクトの移行を行う

プロジェクトを選択すると、ツールで実行される移行ステップの一覧が表示されます。

Upgrade Steps

Entrypoint: C:\Work\net45\cs\MatchingGame\MatchingGame.csproj
Current Project: C:\Work\net45\cs\MatchingGame\MatchingGame.csproj

1. [Next step] Back up project
2. Convert project file to SDK style
3. Clean up NuGet package references
    a. Duplicate reference analyzer
    b. Package map reference analyzer
    c. Target compatibility reference analyzer
    d. Upgrade assistant reference analyzer
    e. Windows Compatibility Pack Analyzer
    f. MyDotAnalyzer reference analyzer
    g. Newtonsoft.Json reference analyzer
    h. Transitive reference analyzer
4. Update TFM
5. Update NuGet Packages
    a. Duplicate reference analyzer
    b. Package map reference analyzer
    c. Target compatibility reference analyzer
    d. Upgrade assistant reference analyzer
    e. Windows Compatibility Pack Analyzer
    f. MyDotAnalyzer reference analyzer
    g. Newtonsoft.Json reference analyzer
    h. Transitive reference analyzer
6. Add template files
7. Update Winforms Project
    a. Default Font API Alert
    b. Winforms Source Updater
8. Upgrade app config files
    a. Convert Application Settings
    b. Convert Connection Strings
    c. Disable unsupported configuration sections
9. Update source code
    a. Apply fix for UA0002: Types should be upgraded
    b. Apply fix for UA0012: 'UnsafeDeserialize()' does not exist
    c. Apply fix for UA0014: .NET MAUI projects should not reference Xamarin.Forms namespaces
    d. Apply fix for UA0015: .NET MAUI projects should not reference Xamarin.Essentials namespaces
10. Move to next project

今回の例としては「1」~「10」までのステップがあり、それぞれのステップを実行することで移行を行うことができます。以降の記事では、重要となるステップのみを記載するため、一部のステップへの実行を省略しますが、指定されるコマンドにしたがい処理の実行を行ってください。

バックアップの作成(1.Back up project)

対象とするフォルダの末尾に「.backup」が付与されたバックアップフォルダを作成します。規定のパス以外にも任意にパスを選択でき、移行を行うプロジェクト毎にプロジェクトのフォルダがバックアップフォルダにコピーされます。

[**:**:** INF] Applying upgrade step Back up project
Please choose a backup path
   1. Use default path [C:\Work\net45\cs.backup]
   2. Enter custom path

[**:**:** INF] Backing up C:\Work\net45\cs\MatchingGame to C:\Work\net45\cs.backup\MatchingGame
[**:**:** INF] Project backed up to C:\Work\net45\cs.backup\MatchingGame
[**:**:** INF] Upgrade step Back up project applied successfully

プロジェクトファイルのアップグレード(2.Convert project file to SDK style)

対象となるプロジェクトを .NET Frameworkプロジェクト形式から .NET SDKプロジェクト形式に移行します。実行することでpackages.configによって参照されるNuGetパッケージがプロジェクトファイルに移行されます。

[**:**:** INF] Applying upgrade step Convert project file to SDK style
[**:**:** INF] Converting project file format with try-convert, version 0.3.326103+8aa571efd8bac422c95c35df9c7b9567ad534ad0
[**:**:** INF] Recommending Windows TFM net6.0-windows because the project either has Windows-specific dependencies or builds to a WinExe
C:\Work\net45\cs\MatchingGame\MatchingGame.csproj contains an App.config file. App.config is replaced by appsettings.json in .NET Core. You will need to delete App.config and migrate to appsettings.json if it's applicable to your project.
[**:**:** INF] Converting project C:\Work\net45\cs\MatchingGame\MatchingGame.csproj to SDK style
[**:**:** INF] Project file converted successfully! The project may require additional changes to build successfully against the new .NET target.
[**:**:** INF] Upgrade step Convert project file to SDK style applied successfully
Please press enter to continue...

[**:**:** INF] Initializing upgrade step Clean up NuGet package references
[**:**:** INF] Initializing upgrade step Duplicate reference analyzer
[**:**:** INF] No package updates needed
[**:**:** INF] Initializing upgrade step Package map reference analyzer
[**:**:** INF] No package updates needed
[**:**:** INF] Initializing upgrade step Target compatibility reference analyzer
[**:**:** INF] No package updates needed
[**:**:** INF] Initializing upgrade step Upgrade assistant reference analyzer
[**:**:** INF] Reference to .NET Upgrade Assistant analyzer package (Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers, version 0.3.326103) needs to be added
[**:**:** INF] Initializing upgrade step Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'

NuGet参照のクリーンアップ(3.Clean up NuGet package references)

このステップでは、パッケージ参照の分析を行い不要な参照の削除を行います。今回では、「MetroFramework.Design」、「MetroFramework.Fonts」、「MetroFramework.RunTime」の参照を削除しています。

3. [Complete] Clean up NuGet package references
    a. [Complete] Duplicate reference analyzer
    b. [Complete] Package map reference analyzer
    c. [Complete] Target compatibility reference analyzer
    d. [Complete] Upgrade assistant reference analyzer
        1. [Complete] Add package 'Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers'
    e. [Complete] Windows Compatibility Pack Analyzer
    f. [Complete] MyDotAnalyzer reference analyzer
    g. [Complete] Newtonsoft.Json reference analyzer
    h. [Complete] Transitive reference analyzer
        1. [Complete] Remove package 'MetroFramework.Design'
        2. [Complete] Remove package 'MetroFramework.Fonts'
        3. [Complete] Remove package 'MetroFramework.RunTime'

TFM の変更(4.Update TFM)

このステップでは、TFMを .NET Frameworkから提案されたSDKに変更します。今回はnet6.0-windowsが対象となります。

[**:**:** INF] Applying upgrade step Update TFM
[**:**:** INF] Recommending Windows TFM net6.0-windows because the project either has Windows-specific dependencies or builds to a WinExe
[**:**:** INF] Updated TFM to net6.0-windows
[**:**:** INF] Upgrade step Update TFM applied successfully

実行時にnet6.0-windows7.0への互換性がない旨のエラーが表示されますが、ツールがプロジェクトに対して対処の必要がないと判断した場合は次のステップが自動的にスキップされます。

NuGet パッケージの移行(5.Update NuGet Packages)

このステップでは、プロジェクトのNuGetパッケージを、更新されたTFM(net6.0-windows)をサポートするバージョンに更新します。今回では、「Microsoft.Windows.Compatibility」の適用を行っています。

[**:**:** INF] Applying upgrade step Add package 'Microsoft.Windows.Compatibility'
[**:**:** INF] Adding package reference: Microsoft.Windows.Compatibility, Version=6.0.0
[**:**:** INF] Upgrade step Add package 'Microsoft.Windows.Compatibility' applied successfully
[**:**:** INF] Applying upgrade step Windows Compatibility Pack Analyzer
[**:**:** INF] Upgrade step Windows Compatibility Pack Analyzer applied successfully

Windows Formsプロジェクト固有の更新プログラム(7.Update Winforms Project)

Windows Forms内の既定フォントについて、変更されていることを確認します。規定フォント変更に関する詳細については以下のページを参照してください。

[**:**:** INF] Applying upgrade step Default Font API Alert
[**:**:** WRN] Default font in Windows Forms has been changed from Microsoft Sans Serif to Seg Segoe UI, in order to change the default font use the API - Application.SetDefaultFont(Font font). For more details see here - https://devblogs.microsoft.com/dotnet/whats-new-in-windows-forms-in-net-6-0-preview-5/#application-wide-default-font.
[**:**:** INF] Upgrade step Default Font API Alert applied successfully

次に、SetHighDpiModeメソッドを呼び出すようにスタートアップロジックの更新を行います。

[**:**:** INF] Applying upgrade step Winforms Source Updater
[**:**:** WRN] HighDpiMode needs to set in Main() instead of app.config or app.manifest - Application.SetHighDpiMode(HighDpiMode.<setting>). It is recommended to use SystemAware as the HighDpiMode option for better results.
[**:**:** INF] Updated Program.cs file at C:\Work\net45\cs\MatchingGame\Program.cs with HighDPISetting set to SystemAware
[**:**:** INF] Upgrade step Winforms Source Updater applied successfully
[**:**:** INF] Applying upgrade step Update Winforms Project
[**:**:** INF] Upgrade step Update Winforms Project applied successfully

移行の完了(10.Move to next project)

対象とするプロジェクトの移行完了後、移行するプロジェクトがまだ残っている場合は次に移行を行うプロジェクトを選択するように促されます。移行を行うプロジェクトが存在しない場合は、「移行の最終処理」ステップに進みます。

1. [Next step] Finalize upgrade

Choose a command:
   1. Apply next step (Finalize upgrade)
   2. Skip next step (Finalize upgrade)
   3. See more step details
   4. Configure logging
   5. Exit
[**:**:** INF] Applying upgrade step Finalize upgrade
[**:**:** INF] Upgrade step Finalize upgrade applied successfully
Please press enter to continue...

[**:**:** INF] Upgrade has completed. Please review any changes.

移行が完了すると、移行されたWindows Formsアプリ(MatchingGame)のプロジェクトが次のXMLのように更新されています。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net6.0-windows</TargetFramework>
    <OutputType>WinExe</OutputType>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <UseWindowsForms>true</UseWindowsForms>
    <ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\MatchingGame.Logic\MatchingGame.Logic.csproj" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="MetroFramework" Version="1.2.0.3" />
    <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
    <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
    <PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.3.330701">
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Windows.Compatibility" Version="6.0.0" />
  </ItemGroup>
</Project>

<TargetFramework>に「net6.0-windows」が設定され、 .NET 6に移行が行われていることが分かります。また、 .NET アップグレード アシスタントが移行プロセスを続けるのに役立つアナライザー「Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers」が追加されています。

移行後のプロジェクト

移行後の動作検証

プロジェクトの移行が完了したため、正しく動作するかテストを行ってみましょう。

移行対象としたサンプルプログラムでは、MatchingGame.Logicプロジェクトがコンパイルに失敗します。

移行後のエラー

このプロジェクトでは、Windows Registryが使用されていますが、 .NET 6から直接提供されないためWindows RegistryへのアクセスとしてNuGetパッケージ「Microsoft.Win32.Registry」をプロジェクトに追加する必要があります。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <OutputType>Library</OutputType>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
    <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
    <PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.3.330701">
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
	  <PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
  </ItemGroup>
</Project>

コンパイルエラーが解消できたらMatchingGameプロジェクトを実行します。移行前と同じ動作が行えていれば成功です。

移行したアプリケーションを実行

さいごに

以上が .NET アップグレード アシスタントを使って .NET FrameworkのWindows Formsアプリを .NET 6にアップグレードする方法でした。今回はGitHubにある公式サンプルで試してみましたが、次回は弊社のコンポーネントを組み込んだアプリケーションの移行も試してみたいと思います。