Windows Server 2019 / 2022 上で .NET 9 の .NET MAUI(WinUI 3)アプリを「EXE 配布だけで動かしたい。サーバー側には .NET ランタイムを一切入れたくない」――そんな要件は、オンプレや閉域網の環境ではよくあります。この記事では、self-contained 発行 + WindowsAppSDKSelfContained を使ったときに本当にランタイム不要で動くのか、どんな落とし穴があるのかを、Windows Server 視点で丁寧に解説します。
.NET MAUI(Windows)と Windows Server 2019/2022 の対応関係
.NET MAUI Windows の公式サポート OS
.NET MAUI の Windows 向け実装は、WinUI 3 + Windows App SDK を使用するデスクトップアプリです。公式ドキュメントでは、Windows 対応として次が明記されています。
- Windows 11
- Windows 10 バージョン 1809 以降(WinUI 3 ベース)
WinUI 3 は Windows 10 1809(ビルド 17763)以降で動作する UI フレームワークであり、それより古い OS(たとえば Windows 7 / 8.1 / 10 1607 など)は対象外です。
Windows Server 2019 / 2022 は要件を満たすのか
サーバー OS はクライアント OS とビルド番号を共有しているので、WinUI 3 / .NET MAUI の最小要件を満たしているかどうかは、対応するクライアント版を見れば判断できます。
| サーバー OS | ベースとなるクライアント OS / ビルド | MAUI/WinUI 3 の観点 | コメント |
|---|---|---|---|
| Windows Server 2016 | Windows 10 1607(ビルド 14393) | ×(要件未満) | WinUI 3 の最小要件 1809 に届かず、.NET MAUI アプリは動作しないと明言されている。 |
| Windows Server 2019 | Windows 10 1809(ビルド 17763)と同世代 | ◯(要件を満たす) | WinUI 3 の要件を満たすため、MAUI Windows アプリを実行可能とされている。 |
| Windows Server 2022 | Windows 10 21H2 世代(「Iron」コードベース) | ◯(要件を満たす) | クライアント版 Windows 10 21H2 以上に相当するため、WinUI 3 / .NET MAUI の要件を十分に超える。 |
また、サードパーティコンポーネントベンダーの .NET MAUI システム要件にも、Windows Server 2019 / 2022 が明示的に含まれており、実運用で利用されていることが分かります。
したがって、Windows Server 2019 / 2022(デスクトップ エクスペリエンス版)であれば、OS バージョン要件の面では .NET MAUI Windows アプリを実行可能と考えて問題ありません。
Server Core は対象外
.NET MAUI Windows アプリは WinUI 3 を使った対話型 GUI アプリです。GUI を持たない Server Core 環境では動作しないため、必ず「デスクトップ エクスペリエンス」付きエディションを使う前提で考えてください。
self-contained / WindowsAppSDKSelfContained の正体
self-contained は「.NET ランタイム同梱」
.NET には大きく分けて 2 つの配布モードがあります。
| 項目 | Framework-dependent(既定) | Self-contained |
|---|---|---|
| .NET ランタイム | マシンに別途インストールされているものを利用 | アプリの出力にランタイム一式が同梱される |
| 配布サイズ | 小さい | ランタイム込みなので大きい |
| 更新 | .NET ランタイムのセキュリティ更新を OS / 管理者が配布すれば、アプリも恩恵を受ける | アプリ側にランタイムが埋め込まれているため、パッチ適用には再ビルド&再配布が必要 |
| サーバー環境への影響 | サーバーにランタイムをインストールするため、標準イメージを汚したくない場合には嫌われがち | アプリをコピーするだけでよく、サーバー側に .NET をインストールする必要がない |
self-contained 発行を行うと、アプリの出力フォルダに .NET ランタイム DLL やホスト EXE が丸ごと入るため、ターゲットマシンに .NET ランタイムをインストールする必要はありません。
ただし、.NET ランタイム自身が依存しているネイティブコンポーネント(OS に標準で含まれる Win32 API や一部の VC++ ランタイムなど)は、OS 側に存在していることが前提です。Windows Server 2019/2022 のようなモダンな OS であれば、特別な追加インストール無しで満たされます。
.NET 8/9 からの重要な変更:RID を指定しても self-contained にはならない
以前の .NET(~7 まで)では、<RuntimeIdentifier> を指定すると暗黙的に SelfContained=true と解釈される挙動がありました。しかし、.NET 8 以降(.NET 9 を含む)ではこの挙動が変更されています。
- .NET 7 以前:
RuntimeIdentifierを指定すると既定で self-contained 扱い - .NET 8 以降:RuntimeIdentifier を指定しても既定は framework-dependent(ランタイム別インストール前提)
そのため .NET 9 以降で「ランタイム同梱」にしたい場合は、csproj か CLI のどちらかで SelfContained=true または --self-contained true を明示する必要があります。
WindowsAppSDKSelfContained=true の意味
.NET MAUI Windows アプリは、.NET ランタイムだけでなく Windows App SDK(WinUI 3 周り)にも依存します。この部分にも、framework-dependent / self-contained という 2 種類の配布モードがあります。
WindowsAppSDKSelfContained(プロジェクトファイルの表記では WindowsAppSdkSelfContained)プロパティは、Windows App SDK ランタイムをアプリ側に同梱するかどうかを制御します。
| プロパティ | 役割 | true のときに同梱されるもの |
|---|---|---|
SelfContained / --self-contained | .NET アプリ共通の self-contained 設定 | .NET ランタイム & BCL(System.* など) |
WindowsAppSdkSelfContained | Windows App SDK 固有の self-contained 設定 | WinUI 3 / Windows App SDK ランタイム一式 |
特に WindowsPackageType=None(MSIX ではなく EXE 配布) の場合、WindowsAppSdkSelfContained=true を付けないと ターゲットマシン側に Windows App SDK ランタイムを事前インストールする必要が出てきます。
まとめると、「.NET ランタイム」と「Windows App SDK ランタイム」は別物であり、それぞれに self-contained 設定が存在します。サーバー側に何もインストールしたくないなら、両方の self-contained を有効にするのがポイントです。
結論:self-contained 発行なら .NET ランタイムの別途インストールは不要
前提となる発行コマンド
質問で挙げられているような .NET 9 / MAUI Windows アプリを self-contained で発行する場合、CLI では次のようなコマンドが実務的に扱いやすい形です。
dotnet publish -f net9.0-windows10.0.19041.0 -c Release ^
-r win10-x64 --self-contained true ^
-p:WindowsPackageType=None ^
-p:WindowsAppSDKSelfContained=true
REM (任意)-p:PublishSingleFile=true
-f net9.0-windows10.0.19041.0… .NET 9 + Windows 10 SDK 19041 向け TFM。MAUI Windows の公式例も 19041 を推奨。-r win10-x64… 64bit Windows 10/11 / Server 2019/2022 向け RID--self-contained true… .NET ランタイムを同梱-p:WindowsAppSDKSelfContained=true… Windows App SDK ランタイムを同梱-p:WindowsPackageType=None… MSIX ではなく「アンパッケージド EXE」として出力する指定
このようにビルドされた出力(publish フォルダ)一式を Windows Server 2019 / 2022 にコピーすれば、サーバー側に .NET 9 ランタイムや Windows App SDK ランタイムをインストールしなくても起動可能です。
| 項目 | self-contained + WindowsAppSDKSelfContained の場合 | framework-dependent の場合 |
|---|---|---|
| サーバーに必要な .NET ランタイム | 不要(アプリに同梱) | 必要(.NET 9 Desktop Runtime などをインストール) |
| サーバーに必要な Windows App SDK ランタイム | 不要(アプリに同梱) | 必要(Windows App SDK ランタイムを別途配布) |
| OS バージョン要件 | Windows 10 1809 相当以上(= Windows Server 2019 / 2022 は要件を満たす) | |
つまり、「RID を指定した self-contained 発行 + WindowsAppSDKSelfContained=true」でビルドされた EXE であれば、Windows Server 2019/2022 側に .NET ランタイムや Windows App SDK を入れる必要はありません。
一点だけ注意が必要なのは、self-contained でも OS そのもののコンポーネント(Win32 API や WebView2 ランタイムなど)は別扱いであることです。とくに WebView2 については後述します。
実務で使いやすいビルド設定例(csproj)
CLI で毎回オプションを並べるのが面倒な場合、csproj に共通設定として記述しておくと便利です。
<PropertyGroup>
<TargetFramework>net9.0-windows10.0.19041.0</TargetFramework>
<OutputType>WinExe</OutputType>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<WindowsPackageType>None</WindowsPackageType>
<WindowsAppSdkSelfContained>true</WindowsAppSdkSelfContained>
<PublishSingleFile>false</PublishSingleFile>
<IncludeNativeLibrariesForSelfExtract>false</IncludeNativeLibrariesForSelfExtract>
</PropertyGroup>
この設定を入れておけば、あとは単純に dotnet publish -c Release するだけで、Windows Server 2019/2022 にそのままコピーして実行できる EXE が生成されます。
Windows Server 環境ならではの注意点・落とし穴
1. WebView / BlazorWebView を使うなら WebView2 ランタイムが必要
.NET MAUI の WebView や BlazorWebView(Blazor Hybrid)は、内部で Microsoft Edge WebView2 を利用します。この WebView2 は、専用の「WebView2 ランタイム」がターゲットマシンに存在することが前提です。
WebView2 ランタイムには以下の 2 モデルがあります。
| モード | 概要 | メリット | デメリット |
|---|---|---|---|
| Evergreen(推奨) | マシンに 1 つだけ WebView2 ランタイムをインストールし、複数アプリで共有。更新は Windows Update / WSUS などで自動。 | ディスク容量を節約 / 自動アップデート / セキュリティ更新が楽 | サーバー側にランタイムをインストールする必要がある |
| Fixed Version | 特定バージョンの WebView2 ランタイムをアプリ側が同梱して配布。 | サーバーに WebView2 をインストールしなくても動作 / バージョンを完全にコントロール可能 | アプリサイズが +200MB 前後増える / 更新はアプリ側の再配布が必要 |
self-contained = WebView2 も勝手に入ってくれる、ではない点に注意してください。WebView2 はあくまで独立したコンポーネント扱いであり、Evergreen なら OS 側にインストール、Fixed Version ならアプリ側で同梱、という設計になります。
MAUI アプリで WebView / BlazorWebView を一切使っていないのであれば、WebView2 ランタイムは不要です。
2. インストール先と書き込み権限
アンパッケージド EXE で配布する場合、MSIX のような宣言型マニフェストは無く、アプリがどこに書き込もうとするかは完全にアプリ側の実装次第です。
- 設定ファイル / キャッシュ / ログなどは、
%LocalAppData%や%ProgramData%のような書き込み可能なパスを使う C:\Program Files直下にインストールする場合、アプリ自身のフォルダに書き込みを行わない(WebView2 のユーザーデータフォルダも含む)
実際、固定版 WebView2 ランタイムを含む MAUI Blazor アプリを Program Files 配下に配置したところ、WebView2 がユーザーデータを作成できずに起動失敗する、という事例も報告されています。
Windows Server ではサーバー管理者が NTFS 権限をかなりシビアに設定しているケースが多いため、ユーザーデータや一時ファイルの場所は設計段階で明示的に決めておくのが安全です。
3. SmartScreen とコード署名
self-contained の EXE はサイズも大きく、初回起動時に SmartScreen の警告 が出やすくなります。企業内配布であっても、コードサイン証明書で署名した EXE を配布した方が運用は圧倒的に楽です。
- CI/CD(GitHub Actions / Azure Pipelines など)で署名ステップを組み込み、常に署名済みバイナリを生成
- Windows Server 側のグループポリシーで、「信頼された発行元」のみに警告を緩和する設定を行う
SmartScreen を「無効化してしまう」のはセキュリティ観点でお勧めできません。あくまで正しい署名とポリシー設定で、必要なところだけ警告を抑えるのがベストプラクティスです。
4. AnyCPU ではビルドできないケースに注意
WindowsAppSDKSelfContained を有効にすると、プロジェクトのアーキテクチャが AnyCPU のままではビルドエラーになることがあります。
代表的なエラー:
WindowsAppSDKSelfContained requires a supported Windows architecture.
The platform 'AnyCPU' is not supported for Self Contained mode.
この場合は、ソリューション全体を x64 固定(または arm64 固定)に揃える必要があります。Windows Server 2019/2022 は x64 専用 OS なので、x64 ビルド一択と考えておけば問題ありません。
5. 「.NET ランタイムを入れてください」と言われてしまう場合
self-contained を指定したつもりなのに、実行時に「.NET Desktop Runtime 9.0 をインストールしてください」といったダイアログが表示される場合は、次のような原因が考えられます。
dotnet publishでは--self-containedを指定したが、dotnet build --no-restore側で--self-containedを付けていない(--no-build併用時に起こりがち)- MSIX パッケージとして配布しており、パッケージ側が framework-dependent 構成になっている
- 古いテンプレートやカスタム MSIX プロジェクトを使っており、
SelfContained設定がすべての構成に反映されていない
まずは publish フォルダに .NET ランタイム DLL(System.Private.CoreLib.dll など)が一式含まれているか、EXE と同じ階層に hostpolicy.dll / hostfxr.dll が存在するかを確認すると切り分けがしやすくなります。
Windows Server 2019/2022 での動作確認チェックリスト
実際にサーバーへ配置する前後で、次の観点をチェックしておくとトラブルを減らせます。
| カテゴリ | チェック項目 |
|---|---|
| OS / エディション | Windows Server 2019 / 2022 であること(バージョン情報で確認) 「デスクトップ エクスペリエンス」付きインストールであること |
| ビルド設定 | SelfContained=true または --self-contained true を明示している WindowsAppSdkSelfContained=true を指定している RuntimeIdentifier=win10-x64(または -r win10-x64)で x64 固定にしている AnyCPU 構成が残っていない(全プロジェクトの Platform が x64) |
| WebView2 | WebView / BlazorWebView を使用している場合、サーバー側に WebView2 Evergreen ランタイムをインストール済みか、Fixed Version を同梱している Fixed Version を使う場合、ユーザーデータフォルダがユーザー書き込み可能な場所にある |
| 配置 / 権限 | publish フォルダ一式をコピーしている(EXE 単体だけを抜き出していない) ログ・キャッシュ先が %LocalAppData% or %ProgramData% 等の書き込み可能なパス |
| セキュリティ | EXE にコード署名を行っている ウイルス対策ソフトがアプリをブロックしていないか確認(イベントログやウイルス対策ログをチェック) |
| 実行テスト | RDP などの対話セッションでログオンし、アプリを手動起動して UI が正常に表示されるか確認 イベントビューアーの「アプリケーション」ログに例外が出ていないか確認 |
サービス常駐させたいときの設計上の注意
MAUI アプリはあくまでUI を持つデスクトップアプリであり、Windows サービスとしての常駐実行は前提にされていません。Session 0(サービスセッション)では UI が表示できないため、サービス化してもまともに動作しません。
もしサーバー側で常駐処理を行いたい場合は、次のようなアーキテクチャを推奨します。
- .NET Worker Service / Windows サービスとして動く「バックエンドプロセス」を別途作成(これは MAUI ではなく通常の .NET アプリ)
- MAUI クライアントはそのバックエンドと HTTP / gRPC / メッセージキュー等で通信する
- Windows Server 上には「バックエンドサービス」と「必要であれば UI クライアント」の両方を配置する
こうすることで、UI の有無に関係なくバックグラウンド処理を安定運用できます。
実戦的な発行・配布フローの例
最後に、Windows Server 2019/2022 で MAUI Windows アプリを self-contained 配布する際の、現実的なフローを示します。
- 開発環境の整備
- 開発 PC に .NET 9 SDK / .NET MAUI 9 ワークロードをインストール
- Visual Studio / CLI で Windows 向け MAUI アプリを作成
- ビルド設定
csprojにRuntimeIdentifier=win10-x64/SelfContained=true/WindowsAppSdkSelfContained=trueを記述- 構成は Release / x64 固定に統一
- 発行
- CI から
dotnet publish -c Releaseを実行 - 成果物として
publishフォルダ一式をアーティファクト化 - ビルド後ステップで EXE にコード署名を実施
- CI から
- パッケージング
- 単純な配布なら ZIP(publish フォルダを丸ごと圧縮)
- インストーラが必要なら WiX などで MSI を作成(publish フォルダをそのまま取り込む)
- サーバーへの展開
- Windows Server 2019/2022(デスクトップ エクスペリエンス)に ZIP / MSI を配布
- 適切なフォルダ(例:
C:\Apps\YourMauiApp)に展開 - 必要に応じてショートカットや RDS RemoteApp の設定を行う
- 動作確認
- RDP でサーバーにログオンし、EXE を起動
- WebView2 を使っている場合は、WebView2 ランタイムの有無を確認(Evergreen を事前にインストールするか、自アプリに Fixed Version を同梱)
- イベントログ・ログファイルにエラーが出ていないか確認
まとめ:ひとことで言うと
Windows Server 2019/2022 上で .NET 9 の .NET MAUI Windows アプリを EXE 配布だけで動かしたい場合、
--self-contained true(またはSelfContained=true)で .NET ランタイムを同梱するWindowsAppSdkSelfContained=trueで Windows App SDK ランタイムも同梱する- OS は Windows Server 2019 / 2022(デスクトップ エクスペリエンス)であること
- WebView2 を使うなら WebView2 ランタイム(Evergreen か Fixed Version)を別途用意する
――この 4 点さえ押さえておけば、サーバー側に .NET ランタイムをインストールせずとも MAUI アプリを動かすことができます。あとは企業環境特有の要件(署名・権限・インストーラ形態)に合わせて、ビルドと配布のフローを整えていきましょう。

コメント