【.NET 9】.NET MAUIのMicrosoft.Maui.Controls Versionは明示すべき?$(MauiVersion)の確認方法と9系へ更新する手順

.NET 9 へ移行して .NET MAUI をビルドしようとすると、csproj に <PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" /> が残っていて「Version を明示すべき?」「今どのバージョン?」と迷いがちです。9 系へ揃える考え方と、バージョン確認・更新の具体手順をまとめます。

目次

この記事が解決すること

  • .NET 9(.NET MAUI)で Microsoft.Maui.Controls の Version を明示すべきかの判断基準
  • $(MauiVersion) が指している実体(=実際に解決される NuGet バージョン)の確認方法
  • プロジェクト全体で MAUI のバージョンを揃えて、移行時のハマりを減らす運用パターン

前提:Microsoft.Maui.Controls は「どこから」参照されるのか

Microsoft.Maui.Controls は .NET MAUI の UI(Controls / XAML)を提供する中心パッケージです。ただし、MAUI のアプリ プロジェクトでは、ふつう csproj に明示的な PackageReference を書かなくても動きます。理由は、MAUI アプリは <UseMaui>true</UseMaui> を有効にすることで、MAUI SDK(ワークロード/SDK)が必要な参照をまとめて面倒を見てくれるからです。

一方で、次のようなケースでは Microsoft.Maui.Controls を 明示的に参照している(あるいは参照せざるを得ない)ことがあります。

  • MAUI コントロールを含む クラス ライブラリ(カスタムコントロールや共通 UI コンポーネント)を作っている
  • ソリューション内で複数の MAUI 関連パッケージを使っており、中央集権的に Version を揃えるために $(MauiVersion) を導入している
  • 過去のテンプレートや手元の運用で PackageReference を足しており、移行後も残っている
プロジェクトの種類Microsoft.Maui.Controls を直接参照する必要Version 管理のポイント
MAUI アプリ(単体)基本的に不要(UseMaui が参照を供給)SDK/ワークロード更新が最重要。明示参照しているなら 9 系へ揃える
MAUI クラス ライブラリ必要になりやすい(ビルド時に参照が必要)参照するなら 9.x の具体値で固定し、ソリューション全体で統一
複数プロジェクト(大規模)ケースによるDirectory.* でバージョン統一、dotnet list package で実解決を定期監査

結論:.NET 9 へ移行するなら Microsoft.Maui.Controls も 9 系へ見直す

質問の核心は「Version を明示すべきか」ですが、移行期に実務で一番トラブルが出るのは「8 系のまま残ってしまう」ことです。プロジェクトが .NET 9 をターゲットにしているのに、Microsoft.Maui.Controls だけが 8.x(あるいは別の MAUI 系パッケージが 8.x)だと、復元(restore)やビルドで不整合が起きやすくなります。

そのため、.NET 9 へ上げるなら次を押さえるのが結論です。

  • 明示参照している場合:Microsoft.Maui.Controls の Version は 9.x に更新する($(MauiVersion) 経由でも同じ)
  • 明示参照していない場合:MAUI SDK/ワークロードを .NET 9 用に更新し、結果として 9 系が解決される状態を作る
  • 複数プロジェクト:「一部だけ 8.x」の混在を作らない(これが移行事故の最大要因)

「Version を明示すべき?」の判断基準

Microsoft.Maui.Controls の Version を csproj に具体値で書くべきかは、プロジェクトの性質と運用(再現性 vs 追従性)で決めるのが現実的です。迷ったら、次の表のどれに近いかで決めるとブレません。

方針csproj の状態メリット注意点おすすめ度
MAUI SDK/ワークロードに任せるMicrosoft.Maui.Controls の PackageReference を書かない余計な固定がなく、SDK 更新で自然に追従できるCI/開発機の SDK がズレると結果が変わり得る。環境統一が前提MAUI アプリでは高い
csproj で具体値を固定Version="9.0.0"(例)のように固定ビルド再現性が高い。CI と開発機の差が出にくい更新作業が発生。パッチの取り込みは自分で回す必要ライブラリ/大規模では高い
プロパティで統一($(MauiVersion))Version="$(MauiVersion)" を採用複数プロジェクトを一括更新できる。差分が小さくレビューしやすい定義場所が分からないと混乱する。二重定義で意図せず上書きも複数プロジェクトで最有力

つまり、質問の形(Version="$(MauiVersion)")で運用しているなら、「明示する/しない」よりも「$(MauiVersion) が 9.x を指しているか」が最重要です。逆に、アプリ プロジェクトが単体で、不要な PackageReference が残っているだけなら、いったん消して SDK 側に寄せるのも有効です(ただし、チーム/CI の SDK 統一が前提)。

今使っている Microsoft.Maui.Controls のバージョンを確認する方法

「自分が今どのバージョンを使っているか」を確実に知るには、“csproj に書かれている値”ではなく、“NuGet が実際に解決した値”を見る必要があります。確認手段は大きく 4 つあります。

確認方法何が分かる強み弱み
csproj / props を読む「意図した指定」最速。どこで固定しているかが分かる依存解決で変わる場合がある(中央管理/推移的参照)
dotnet list package「実際に解決されたバージョン」CLI だけで完結。CI でも同じ手順で確認できる結果が多いので、絞り込みの工夫が必要
Visual Studio の NuGet 画面直接/推移的の依存関係GUI で見やすい。更新もその場でできる環境差(VS の設定/SDK)を吸収しないことがある
assets / lock ファイル解決結果の実体最終結果を追跡できる(差分比較にも強い)ファイル場所が分かりにくい。内容が巨大

CLI だけで確認する:dotnet list package

環境に依存せず確実なのは CLI です。MAUI プロジェクト(またはライブラリ)直下で次を実行します。

dotnet list package
dotnet list package --include-transitive

--include-transitive を付けると、直接参照していないのに引っ張られているバージョンも見えます。Microsoft.Maui.Controls だけを見たい場合は、出力をフィルターします(PowerShell 例)。

dotnet list package --include-transitive | Select-String &quot;Microsoft.Maui.Controls&quot;

ここに表示された値が、あなたの環境で 実際に復元されている Microsoft.Maui.Controls のバージョンです。$(MauiVersion) を使っていても、最終的には具体値として解決されて出てきます。

Visual Studio で確認する:インストール済み/推移的を分けて見る

Visual Studio を使っているなら、NuGet パッケージ マネージャーで Microsoft.Maui.Controls を検索し、インストール済み(Installed)と推移的(Transitive)のどちらに出ているかを見ます。

  • Installed に出る:どこかのプロジェクトが直接参照している(csproj に書いている)
  • Transitive に出る:SDK や他パッケージ経由で解決されている(csproj に直接は無い)

更新する場合も、同じ画面から 9.x 系を選んでアップデートできます。GUI が使えない環境(軽量 IDE / CI)では、次の「props で固定」運用が効いてきます。

$(MauiVersion) の正体を突き止める(どこで定義されている?)

Version="$(MauiVersion)" で一番多い混乱が、「MauiVersion の定義場所が分からない」です。定義場所はプロジェクト直下とは限らず、ソリューション全体に影響するファイルに置かれていることがあります。

よくある定義場所は次の通りです(上にあるほど頻出)。

  • Directory.Build.props(リポジトリ直下に置いて全プロジェクトへ適用)
  • Directory.Packages.props(Central Package Management を使う場合)
  • 個別の .csproj(プロジェクトだけに適用)
  • CI のビルド引数(例:/p:MauiVersion=...)

探し方はシンプルです。リポジトリのルートで MauiVersion を全文検索します。

# Windows(cmd)
findstr /s /i &quot;&lt;MauiVersion&gt;&quot; *.csproj *.props *.targets

# PowerShell(例)
Get-ChildItem -Recurse -Include *.csproj,*.props,*.targets |
  Select-String -Pattern &quot;&lt;MauiVersion&gt;&quot; -List

定義が見つかったら、その値が 9.x になっているかを確認します。もし 8.x のままなら、.NET 9 へ移行したタイミングで ここを 9 系へ更新するのが最短ルートです。

.NET 8 から .NET 9(.NET MAUI)へ移行するときの更新手順

「とりあえず TargetFramework を net9.0 に変えた」だけだと、MAUI の依存関係が追従せず躓くことがあります。移行を安定させるための手順を、実務で事故が少ない順に並べます。

やること具体例狙いハマりやすい点
開発環境の .NET 9 SDK を揃えるdotnet --version で確認ビルド結果の差を減らす開発者ごとに SDK が違うと再現しない
MAUI ワークロードを更新dotnet workload updateMAUI の実体を最新に更新後は IDE 再起動/再復元が必要なことがある
TargetFramework を .NET 9 系へnet9.0-android など.NET 9 ランタイムに合わせるマルチターゲットの書き換え漏れ
$(MauiVersion) を 9.x に更新<MauiVersion>9.0.0</MauiVersion>参照の一括統一二重定義(別ファイルで上書き)
Microsoft.Maui.* を 9 系へ揃えるNuGet で更新 / props を更新混在を防ぐサードパーティが古い MAUI を要求する場合
復元キャッシュをクリアして検証dotnet nuget locals all --clear古いキャッシュの影響排除初回 restore が少し遅くなる

TargetFramework の例(MAUI アプリ)

MAUI アプリは複数プラットフォームをターゲットにするのが一般的です。移行時は「どれか 1 つだけ net8.0 のまま」が起きやすいので、まとめて見直します。

&lt;PropertyGroup&gt;
  &lt;TargetFrameworks&gt;net9.0-android;net9.0-ios;net9.0-maccatalyst;net9.0-windows10.0.19041.0&lt;/TargetFrameworks&gt;
  &lt;UseMaui&gt;true&lt;/UseMaui&gt;
&lt;/PropertyGroup&gt;

Windows のバージョン(windows10.0.19041.0 の部分)はプロジェクト要件に合わせて調整しますが、少なくとも「net9.0-windows…」へ上げて揃えます。

csproj に Version を固定したい場合の書き方(9.x の具体値)

「CI で毎回同じ成果物を作りたい」「チームで SDK の更新タイミングがバラバラ」など、ビルド再現性を重視するなら、Microsoft.Maui.Controls の Version を 9.x の具体値で固定する運用が向きます。ポイントは 2 つです。

  • 固定するなら MAUI 関連をまとめて固定する(Controls だけ固定してもズレの原因になる)
  • 固定値は ソリューションで 1 箇所に集約する(レビュー/更新が楽)

パターンA:Directory.Build.props で MauiVersion を一括指定

既に $(MauiVersion) を使っているなら、この形が最も移行しやすいです。

&lt;!-- Directory.Build.props(リポジトリ直下) --&gt;
&lt;Project&gt;
  &lt;PropertyGroup&gt;
    &lt;MauiVersion&gt;9.0.0&lt;/MauiVersion&gt;
  &lt;/PropertyGroup&gt;
&lt;/Project&gt;

※上の 9.0.0 は書き方の例です。実運用では、あなたの環境で利用可能な 9.0 系の具体的なパッチ バージョン(例:9.0.1 など)を指定し、更新タイミングをチームで決めると安定します。

個別の csproj では次のように参照します(質問の形そのままです)。

&lt;ItemGroup&gt;
  &lt;PackageReference Include=&quot;Microsoft.Maui.Controls&quot; Version=&quot;$(MauiVersion)&quot; /&gt;
&lt;/ItemGroup&gt;

更新は Directory.Build.props の 1 箇所で済みます。逆に言うと、ここが 8.x のままだと全体が 8.x に引っ張られます。移行時は真っ先に確認すべき場所です。

パターンB:Central Package Management(Directory.Packages.props)で統一

ソリューション規模が大きい場合は、NuGet の中央管理(Central Package Management)に寄せるとさらに整理できます。Version を 1 ファイルに集約でき、csproj から Version を消せます。

&lt;!-- Directory.Packages.props --&gt;
&lt;Project&gt;
  &lt;ItemGroup&gt;
    &lt;PackageVersion Include=&quot;Microsoft.Maui.Controls&quot; Version=&quot;9.0.0&quot; /&gt;
  &lt;/ItemGroup&gt;
&lt;/Project&gt;

※ここでも 9.0.0 は例です。9.0 系の具体値に置き換え、更新ルール(例:月次で確認)を決めておくと「いつの間にか古いまま」が起きにくくなります。

この場合、csproj 側は次のように Version を書きません。

&lt;ItemGroup&gt;
  &lt;PackageReference Include=&quot;Microsoft.Maui.Controls&quot; /&gt;
&lt;/ItemGroup&gt;

どちらのパターンでも大事なのは「9 系で統一し、実解決を確認する」ことです。

アップデート時にやりがちな失敗と、切り分けのコツ

.NET 9 + .NET MAUI の移行で、現場で多い失敗パターンを先に潰しておくと、原因調査の時間が激減します。

症状よくある原因まずやること次の一手
復元/ビルドで互換性エラー(NU1202 など)MAUI パッケージが 8.x のまま混在dotnet list package --include-transitive で 8.x を探す$(MauiVersion) と各 PackageReference を 9.x へ統一
開発者によってビルド結果が違うSDK/ワークロードのバージョン差dotnet --info と dotnet workload list を共有global.json で SDK を固定、更新ルールを決める
Visual Studio では動くが CLI で失敗するVS 側が別の SDK/Workload を使っているCLI と VS の使用 SDK を合わせるVS の更新、ワークロード再インストール/更新
推移的依存で古い MAUI が残るサードパーティ パッケージが古い依存を要求該当パッケージを最新へ更新どうしても必要なら代替/分離、または一時的にバージョン統一で上書き
更新したのに直らないNuGet キャッシュ/obj/bin が古いdotnet clean + キャッシュクリアソリューションのクリーン、再起動、再 restore

運用の現実解:どれくらい「固定」すべきか

「具体値で固定するかどうか」は、正解が 1 つではありません。現場で安定しやすい落としどころは、次のように使い分けることです。

  • 個人開発・小規模:基本は MAUI SDK/ワークロードに寄せる(不要な固定をしない)
  • チーム開発・CI あり:global.json で SDK を固定し、$(MauiVersion) など 1 箇所で 9.x の具体値を管理
  • 長期運用:月次/四半期などで「更新日」を決めてパッチを取り込み、dotnet list package で差分をレビューする

特に $(MauiVersion) を採用するなら、確認手順もセットで覚えるのがコツです。定義の場所(Directory.Build.props など)と、実解決の確認(dotnet list package)の 2 つを押さえておけば、移行後に「気付いたら 8.x に戻っていた」「開発者によって違う」といった事故を防げます。

まとめ

.NET 9 へ移行するなら、Microsoft.Maui.Controls を含む MAUI 関連は 9 系で統一するのが第一です。Version を csproj に明示するかどうかは運用次第ですが、$(MauiVersion) を使っているなら 定義場所の特定と、dotnet list package で実解決を確認する流れを作ると、移行の迷いとトラブルが一気に減ります。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次