.NET 8 と .NET 9 のサポートは2026年11月10日に終わります。この記事を書いている11月7日から数えると、残りは3日です。社内の業務アプリや他社から買ったアプリが .NET 8 や .NET 9 で動いている会社に向けて、影響を受けるアプリの見つけ方と、.NET 10 へ上げる手順をまとめます。
答えの要点は3つです。まず、PC やサーバーに入っているランタイムと、アプリが指定しているランタイムの両方を調べます。次に、アプリごとの配布のしかたを確かめます。フレームワーク依存と自己完結型では、更新の届き方も、移行の作業も違います。そのうえで、Microsoft が勧める .NET 10(2028年11月14日までサポート)へ上げます。間に合わないフレームワーク依存のアプリには、RollForward の設定で .NET 10 のランタイムを使わせ、試験したうえで一時的にしのぐ方法もあります。
対象は Windows で動く業務アプリ(Windows フォーム、WPF、ASP.NET Core、Windows サービス)です。日付と条件は2026年11月7日に Microsoft の資料で確かめた内容です。この記事のコマンドとスクリプトは Microsoft の資料の仕様をもとに書いたもので、執筆に使った環境では実行していません。
2026年11月10日に終わるもの
Microsoft の .NET のサポートポリシーでは、.NET 8 と .NET 9 の終了日はどちらも2026年11月10日です1。この日は毎月の更新が公開される Patch Tuesday にあたり、重大な問題があれば、この日に最後の更新が出る可能性があります2。
終了後もアプリは動き続けます。ただし、セキュリティ更新、不具合の修正、技術サポートは提供されなくなります2。新しく見つかった脆弱性は .NET 8 と .NET 9 では修正されません。
flowchart TB
accTitle: .NET 8と.NET 9のサポート終了後に起きること
accDescr: 2026年11月10日のサポート終了後もアプリは動き続けるが、セキュリティ更新、不具合の修正、技術サポートが提供されなくなるため、.NET 10へ移ることを示す。
EOS["2026年11月10日 サポート終了"] --> RUN["アプリは動き続ける"]
EOS --> STOP["セキュリティ更新と修正が届かない"]
EOS --> SUP["技術サポートを受けられない"]
STOP --> MOVE[".NET 10へ移る"]
SUP --> MOVE
図1: 終了後もアプリは動くが、更新もサポートも届かなくなる。
サポート期間の最後の6か月はメンテナンス期間で、セキュリティの修正だけが提供されます1。.NET 8 と .NET 9 は2026年5月ごろからこの期間に入っていて、セキュリティ以外の修正はすでに止まっています。
| バージョン | 種類 | 公開 | サポート終了 |
|---|---|---|---|
| .NET 8 | LTS | 2023年11月14日 | 2026年11月10日 |
| .NET 9 | STS | 2024年11月12日 | 2026年11月10日 |
| .NET 10 | LTS | 2025年11月11日 | 2028年11月14日 |
表の出典: .NET のサポートポリシー1。
Entity Framework Core(EF Core)のサポートも .NET のリリースに合わせて決まっています。EF Core 8 と EF Core 9 は2026年11月10日に終わります。EF Core 10 の終了日は2028年11月10日と案内されていて、.NET 10 の11月14日とは4日ずれています3。アプリを .NET 10 へ上げるときは、EF Core のパッケージも 10 へ上げます。
LTS の .NET 8 と STS の .NET 9 が同じ日に終わる理由
LTS(長期サポート)のリリースは3年間サポートされます。STS(標準期間サポート)のリリースは、以前は18か月でした。Microsoft は2025年9月に、STS の期間を .NET 9 から24か月に延ばすと発表しました4。.NET 9 の終了日は2026年5月12日から11月10日に移り、1年早く公開された .NET 8 と同じ日になりました。
flowchart TB
accTitle: .NET 9の終了日が.NET 8と同じになった経緯
accDescr: .NET 9はSTSのサポート期間が18か月だったときは2026年5月12日に終わる予定だったが、STSの期間が.NET 9から24か月に延びたため、.NET 8と同じ2026年11月10日に終わることを示す。
N9[".NET 9 STS"] -.->|"以前の18か月"| OLD["2026年5月12日"]
N9 -->|".NET 9からの24か月"| NEW["2026年11月10日"]
N8[".NET 8 LTS 3年"] --> NEW
図2: STSの期間が24か月に延びたので、.NET 9は.NET 8と同じ日に終わる。
期間が延びたのは .NET 9 だけで、.NET 8 の終了日は変わっていません。
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全7件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
対象外の .NET Framework
名前が似ていますが、.NET Framework は .NET 8 や .NET 9 とは別の製品です。.NET Framework はコンポーネントのライフサイクルポリシーに従い、インストールされている Windows のサポートに合わせてサポートされます5。ライフサイクルのページでは、.NET Framework 4.8 と 4.8.1 に終了日が設定されていません。今回の期限は .NET Framework で作ったアプリには関係しません。
flowchart TB
accTitle: .NET Frameworkと.NETのサポートの違い
accDescr: .NET Framework 4.8はWindowsのコンポーネントとしてOSのサポートに合わせてサポートされ、.NET 8と.NET 9は.NETのサポートポリシーに従って2026年11月10日にサポートが終わることを示す。
FX[".NET Framework 4.8"] --> OS["Windowsのサポートに合わせる"]
NET[".NET 8 と .NET 9"] --> OWN[".NETのサポートポリシー"]
OWN --> DATE["2026年11月10日に終了"]
図3: .NET FrameworkはWindowsと一緒に、.NET 8と.NET 9は.NETのサポートポリシーでサポートが決まる。
どちらで作ったアプリかは、プロジェクトファイルの TargetFramework で分かります。net48 のような値なら .NET Framework、net8.0 や net8.0-windows なら .NET 8 です。古い形式のプロジェクトファイルでは、.NET Framework のバージョンが <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> のように書かれています。
なお、.NET Framework 4.6.2 は2027年1月12日に終わります5。4.6.2 を対象にしているアプリは、4.8 か 4.8.1 へ上げる計画も合わせて立てます。.NET Framework から .NET へ移るかどうかの判断の材料は、「.NET Frameworkから.NETへの移行前チェックリスト」にまとめています。
.NET 8 と .NET 9 で動くアプリを見つける
影響を受けるアプリは3か所から調べます。PC やサーバーに入っているランタイム、アプリのフォルダーにある設定ファイル、自社で開発しているアプリのソースコードです。
flowchart TB
accTitle: .NET 8と.NET 9で動くアプリを調べる3か所
accDescr: PCやサーバーに入っているランタイム、アプリのフォルダーにあるruntimeconfig.json、自社開発のプロジェクトファイルの3か所を調べ、結果を合わせてアプリの一覧を作ることを示す。
RT["入っているランタイム"] --> LIST["アプリの一覧"]
CFG["アプリの runtimeconfig.json"] --> LIST
SRC["自社開発のプロジェクトファイル"] --> LIST
図4: ランタイム、アプリの設定ファイル、ソースコードの3か所を合わせて一覧を作る。
入っているランタイムを一覧する
PC やサーバーに入っているランタイムは、次のコマンドで一覧できます6。
dotnet --list-runtimes
1行に1つずつ、Microsoft.NETCore.App 8.0.x [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] のような形で表示されます。Microsoft.NETCore.App は基本のランタイム、Microsoft.WindowsDesktop.App は Windows フォームと WPF のアプリ用、Microsoft.AspNetCore.App は ASP.NET Core のアプリ用です67。dotnet コマンドが見つからない場合は、C:\Program Files\dotnet\shared\ の下のフォルダーを見ても分かります6。
このコマンドが表示するのは、実行した dotnet と同じアーキテクチャのランタイムだけです8。32bit(x86)のランタイムは C:\Program Files (x86)\dotnet に入るので、x86 で動く業務アプリがあるなら、そちらのフォルダーも見ます。.NET 10 以降の dotnet では、--arch x86 を付けると x86 のランタイムを一覧できます。
flowchart TB
accTitle: dotnet --list-runtimesが表示するランタイムの範囲
accDescr: 64bitのdotnetはC:\Program Files\dotnetのx64のランタイムだけを表示し、x86のランタイムはC:\Program Files (x86)\dotnetに入るため、そのフォルダーを見るか、.NET 10以降のdotnetで--arch x86を付けて一覧することを示す。
CMD["dotnet --list-runtimes"] --> X64["x64のランタイムだけ"]
X86["x86のランタイム"] --> DIR["Program Files(x86)の dotnet"]
DIR --> HOW["フォルダーを見るか --arch x86"]
図5: x86のランタイムは別のフォルダーにあり、既定の一覧には出てこない。
8.0 や 9.0 のランタイムが入っていても、それを使うアプリがあるとは限りません。反対に、自己完結型で配ったアプリはランタイムを自分のフォルダーに持っているので、この一覧には出てきません。アプリそのものを調べる必要があるのはこのためです。
アプリの runtimeconfig.json を探す
.NET のアプリの多くは実行ファイルと同じフォルダーに アプリ名.runtimeconfig.json という設定ファイルを持っています。このファイルの framework や frameworks に、アプリが使うランタイムの名前とバージョンが書かれています9。自己完結型で発行したアプリでは、同梱したランタイムが includedFrameworks に書かれます10。
次のスクリプトは指定したフォルダーの下から .NET 8 か .NET 9 を指定している設定ファイルを探し、配布のしかたと合わせて CSV に書き出します。$roots は業務アプリを置いているフォルダーに合わせて変えます。
# .NET 8 か .NET 9 を指定している runtimeconfig.json を探す
$roots = @($env:ProgramFiles, ${env:ProgramFiles(x86)}, $env:LOCALAPPDATA, 'C:\inetpub', 'D:\Apps') |
Where-Object { $_ -and (Test-Path -LiteralPath $_) }
Get-ChildItem -Path $roots -Filter '*.runtimeconfig.json' -Recurse -File -ErrorAction SilentlyContinue |
ForEach-Object {
try {
$opt = (Get-Content -LiteralPath $_.FullName -Raw | ConvertFrom-Json).runtimeOptions
} catch {
return
}
$fx = @($opt.framework) + @($opt.frameworks) + @($opt.includedFrameworks) |
Where-Object { $_ }
[pscustomobject]@{
File = $_.FullName
Tfm = $opt.tfm
Deployment = if ($opt.includedFrameworks) { 'self-contained' } else { 'framework-dependent' }
Frameworks = ($fx | ForEach-Object { "$($_.name) $($_.version)" }) -join ', '
}
} |
Where-Object { $_.Frameworks -match ' (8|9)\.0\.' } |
Export-Csv -Path "$env:USERPROFILE\dotnet8-9-apps.csv" -NoTypeInformation -Encoding UTF8
$env:LOCALAPPDATA は ClickOnce などで利用者ごとに入れたアプリの置き場所で、スクリプトを実行した利用者の分だけを調べます。結果には、.NET の SDK や Visual Studio、PowerShell 7 のような Microsoft 製品の中の設定ファイルも混ざるので、業務アプリの行だけを残します。PowerShell 7 では -Encoding UTF8 が BOM なしの UTF-8 になるので、Excel で日本語のパスが文字化けするときは utf8BOM を指定します。
Deployment の列が framework-dependent のアプリは PC に入っているランタイムで動き、self-contained のアプリは自分のフォルダーのランタイムで動きます。この違いによって、あとで説明する移行の作業が変わります。
flowchart TB
accTitle: runtimeconfig.jsonから配布のしかたを見分ける
accDescr: runtimeconfig.jsonにframeworkかframeworksがあればフレームワーク依存、includedFrameworksがあれば自己完結型と判断し、ファイルが見つからない場合は1ファイルにまとめて発行したアプリの可能性があることを示す。
F["runtimeconfig.json"] --> A{"どの項目があるか"}
A -->|"framework か frameworks"| FDD["フレームワーク依存"]
A -->|"includedFrameworks"| SC["自己完結型"]
N["ファイルが見つからない"] -.-> SF["1ファイルにまとめた発行の可能性"]
図6: runtimeconfig.jsonの項目で、フレームワーク依存か自己完結型かを見分ける。
このスクリプトで見つからないアプリもあります。1ファイルにまとめて発行したアプリ(PublishSingleFile)は、runtimeconfig.json を実行ファイルの中に含めるので、フォルダーに設定ファイルが残りません11。また、他社製のアプリは提供元の資料やサポート窓口で、どの .NET で動いているかを確かめます。
ソースコードとパッケージを確かめる
自社で開発しているアプリについては、プロジェクトファイルの TargetFramework(複数のときは TargetFrameworks)を検索します。C:\src はソースコードを置いているフォルダーに置き換えます。
Get-ChildItem -Path C:\src -Include *.csproj, *.vbproj, *.fsproj, Directory.Build.props, Directory.Build.targets -Recurse -File |
Select-String -Pattern '<TargetFrameworks?\b[^<]*net(8|9)\.0' |
Select-Object Path, LineNumber, Line
$(...) のようにプロパティで値を組み立てている書き方は、この検索では見つかりません。結果に出なかったプロジェクトも、ビルドの出力フォルダーの runtimeconfig.json で確かめます。
参照している NuGet パッケージは dotnet package list で一覧できます。--outdated を付けると新しいバージョンがあるパッケージを、--vulnerable を付けると既知の脆弱性があるパッケージを表示します12。この書き方は .NET 10 の SDK からで、.NET 9 以前の SDK では dotnet list package と書きます。
dotnet package list --outdated
dotnet package list --vulnerable --include-transitive
EF Core や Microsoft.Extensions.* のように .NET と一緒に新しいバージョンが出るパッケージは、8.x や 9.x のまま残っていないかを見ます。
配布のしかたと更新の届き方
棚卸しで分けたフレームワーク依存と自己完結型では、セキュリティ更新の届き方が違います。サポート期間中にどう更新していたかが、移行の作業の中身を決めます。
フレームワーク依存のアプリは PC に入っている共有のランタイムで動きます。アプリを起動すると、同じメジャーバージョンの中でいちばん新しいパッチのランタイムが選ばれます13。インストーラーで入れたランタイムは Microsoft Update で更新されるので7、ランタイムが新しくなれば、アプリを配り直さなくても修正が届きます。
自己完結型のアプリは発行したときのランタイムを同梱しています。ランタイムのバージョンは発行の時点で決まるので13、PC のランタイムが更新されても、その修正はアプリに届きません。修正を届けるには、新しいパッチで発行し直して配る必要があります。
flowchart TB
accTitle: 配布のしかたによるセキュリティ更新の届き方
accDescr: フレームワーク依存のアプリはMicrosoft Updateで共有のランタイムが更新されると修正が届き、自己完結型のアプリは開発者が新しいパッチで発行し直して配らないと修正が届かないことを示す。
MU["Microsoft Update"] --> SHARED["共有のランタイムを更新"]
SHARED --> FDD["フレームワーク依存のアプリ"]
DEV["開発者が発行し直す"] --> SC["自己完結型のアプリ"]
図7: フレームワーク依存のアプリにはランタイムの更新で、自己完結型のアプリには発行し直したときに修正が届く。
Microsoft Update による .NET の更新は、クライアントの Windows には自動更新(Automatic Updates)で配信されます。ただし届くのは、Windows Update の詳細オプションで、ほかの Microsoft 製品の更新プログラムも受け取る設定をオンにした PC だけです14。フレームワーク依存のアプリを動かしている PC では、この設定がオンになっているかを確かめます。サーバーの Windows は自動更新の対象にならず、WSUS か Microsoft Update カタログで配ります。レジストリの AllowAUOnServerOS を設定すると、サーバーでも自動更新で受け取れます7。サーバーで動くフレームワーク依存のアプリについては、そのサーバーのランタイムにこれまでパッチが当たっていたかも確かめます。
11月10日を過ぎると、どちらの配布のしかたでも .NET 8 と .NET 9 の修正は出なくなります。ただし、移行に必要な作業は配布のしかたで違います。
flowchart TB
accTitle: 配布のしかたによる移行の作業の違い
accDescr: フレームワーク依存のアプリは、PCやサーバーに.NET 10のランタイムを入れたうえで.NET 10向けに作り直したアプリを配り、自己完結型のアプリは、ランタイムを入れる作業なしに.NET 10で発行し直したアプリを配ることを示す。
FDD["フレームワーク依存"] --> RT10["PCに.NET 10のランタイムを入れる"]
RT10 --> APP1[".NET 10向けのアプリを配る"]
SC["自己完結型"] --> APP2[".NET 10で発行し直して配る"]
図8: フレームワーク依存は利用者のPCにランタイムを入れる作業が加わり、自己完結型は加わらない。
フレームワーク依存のアプリは、利用者の PC やサーバーに .NET 10 のランタイムを入れる作業が加わります。Windows フォームや WPF のアプリなら .NET Desktop Runtime、ASP.NET Core のアプリなら ASP.NET Core Runtime を入れます7。配布の方式ごとの手間は「Windowsアプリ配布方式の選び方」でも比べています。
.NET 10 へ上げる手順
Microsoft の移行の資料では、アプリを新しい .NET に上げるために必須の変更は、プロジェクトファイルの TargetFramework の書き換えだけです15。ただし、実際の業務アプリでは開発環境、パッケージ、破壊的変更、試験と配布まで含めて進めます。
flowchart TB
accTitle: .NET 10へ上げる作業の順番
accDescr: 開発環境を.NET 10のSDKとVisual Studio 2026にそろえ、TargetFrameworkとパッケージを上げ、破壊的変更を確かめ、移行前のアプリと動作を比べる試験をし、配布したあとで古いランタイムを片付ける順番を示す。
ENV["開発環境をそろえる"] --> TFM["TargetFrameworkとパッケージを上げる"]
TFM --> BRK["破壊的変更を確かめる"]
BRK --> TEST["移行前と動作を比べる"]
TEST --> DEP["配布する"]
DEP --> CLEAN["古いランタイムを片付ける"]
図9: 開発環境から始め、配布が終わってから古いランタイムを片付ける。
開発環境と SDK
Visual Studio で開発している場合、.NET 10 の SDK には Visual Studio 2026 のバージョン18.0以降が必要です7。Visual Studio 2022 のままでは .NET 10 を対象にできないので、開発者の PC に Visual Studio 2026 を入れます。dotnet build でビルドするサーバーには .NET 10 の SDK を入れます。Visual Studio 2022 と 2026 は同じ PC に並べて入れられます15。
チームで使う SDK のバージョンはソリューションのフォルダーに置く global.json で指定できます15。
{
"sdk": {
"version": "10.0.100",
"rollForward": "latestFeature"
}
}
この例では、10.0.100 以降の 10.0 の SDK が使われます。.NET 10 の SDK で新しく加わったコード分析の警告を後回しにしたいときは、プロジェクトファイルに <AnalysisLevel>9.0</AnalysisLevel> を書きます。こうすると、.NET 9 までの規則だけが有効になります15。
TargetFramework とパッケージ
プロジェクトファイルの TargetFramework を書き換えます。Windows フォームや WPF のアプリは -windows の付いた値のまま数字だけを変えます。
<PropertyGroup>
<!-- 変更前: <TargetFramework>net8.0-windows</TargetFramework> -->
<TargetFramework>net10.0-windows</TargetFramework>
</PropertyGroup>
続けて、EF Core や Microsoft.Extensions.* のパッケージを 10.x へ上げます。他社のライブラリは .NET 10 に対応したバージョンが出ているかを確かめます。
.NET 10 を対象にすると、dotnet restore は間接的に参照しているパッケージの脆弱性も警告するようになります16。プロジェクトで TreatWarningsAsErrors を有効にしていると、この警告で復元が失敗することがあります。資料では dotnet nuget why で原因のパッケージを探して上げる方法や、警告を WarningsNotAsErrors で除く方法が示されています。
破壊的変更を確かめる
Microsoft は .NET 10 の破壊的変更を分野ごとに一覧にしています17。全部を読む前に、業務アプリで当たりやすいものから確かめます。
flowchart TB
accTitle: .NET 10の破壊的変更の確かめ方
accDescr: .NET 10の破壊的変更のうち、ビルドが通らなくなるもの、動作が変わるもの、復元やビルドの警告が増えるものに分けて確かめることを示す。
BRK[".NET 10の破壊的変更"] --> BUILD["ビルドが通らない"]
BRK --> RUN["動作が変わる"]
BRK --> WARN["警告が増える"]
BUILD --> FIX1["コードを直す"]
RUN --> FIX2["試験で確かめる"]
WARN --> FIX3["パッケージを上げる"]
図10: 破壊的変更は、ビルド、動作、警告のどこに出るかで確かめ方が違う。
| 変更 | 当たるアプリ | 起きること |
|---|---|---|
空の Grid.ColumnDefinitions / RowDefinitions を禁止18 |
WPF | 中身のない定義があると、エラー MC3063 でビルドが通らない |
| System.Drawing の例外の種類を変更19 | Windows フォームなど | GDI+ の Status.OutOfMemory で OutOfMemoryException ではなく ExternalException が出る |
BackgroundService の ExecuteAsync を全部バックグラウンドで実行20 |
Microsoft.Extensions.Hosting の 10.x を使う Windows サービスや常駐アプリ |
最初の await より前の処理が、起動時にほかのサービスを待たせなくなる |
| 1ファイルのアプリがネイティブ DLL を探す場所を変更21 | P/Invoke を使う1ファイルのアプリ | DefaultDllImportSearchPaths で AssemblyDirectory を含めずに検索パスを指定していると、実行ファイルの隣の DLL を探さない |
dotnet restore が間接参照も監査16 |
すべて | 脆弱性の警告が増え、警告をエラーにする設定では復元が失敗する |
表の変更は、ビルドが通らなくなるもの(WPF の Grid)、動作が変わるもの(System.Drawing、BackgroundService、DLL の検索)、警告が増えるもの(dotnet restore)に分かれます。ビルドのエラーはコードを直し、動作の変化は試験で確かめ、警告はパッケージを上げて解消します。
System.Drawing の変更は catch (OutOfMemoryException) で画像の読み込みの失敗を処理しているコードに影響します。資料は ExternalException も捕まえるよう勧めています19。
BackgroundService の変更は ExecuteAsync の最初の部分で初期化を済ませ、そのあとにほかのサービスを起動する前提で書いたコードに影響します。ほかのサービスより先に済ませたい処理はコンストラクターか StartAsync に移します20。BackgroundService を使う理由は「.NET Generic HostとBackgroundServiceをデスクトップアプリで使う理由」で説明しています。
このほか、Windows フォームでは StatusStrip の既定の描画方法が変わり、WPF と Windows フォームの両方を参照するアプリでは MenuItem と ContextMenu の名前があいまいになります17。画面の見た目は試験で移行前のアプリと並べて見比べます。
移行を手伝うツール
以前は .NET Upgrade Assistant が移行を手伝うツールでしたが、Microsoft はこれを非推奨とし、GitHub Copilot のモダン化のチャットエージェントを使うよう案内しています22。このエージェントは Visual Studio 2026 と、Visual Studio 2022 のバージョン17.14.16以降に含まれています。プロジェクトと依存関係を調べて移行の計画を作り、変更をコミットごとに分けて行います。取り込む前に、エージェントの変更を1つずつ差分で読み、試験で確かめます。
試験と配布
試験では移行前と移行後のアプリを同じ入力で動かし、結果を比べます。帳票の出力、日付や数値の書式、外部の機器やシステムとの通信のように、業務で結果が決まっている処理から先に確かめます。テストのない古いアプリに、今の動作を記録するテストを先に作る方法は「テストのないレガシー業務アプリに安全に手を入れる」で紹介しています。
ビルドと配布の設定にも .NET のバージョンが書かれています。GitHub Actions の setup-dotnet のバージョン、コンテナーの FROM の行、Azure App Service の設定を 10 に変えます15。
flowchart TB
accTitle: 試験から古いランタイムの片付けまで
accDescr: 移行前と移行後のアプリを同じ入力で動かして結果を比べ、ビルドと配布の設定を10に変えて配布し、.NET 8のランタイムを使うアプリが残っていないことを棚卸しで確かめてから古いランタイムを削除することを示す。
CMP["移行前後を同じ入力で比べる"] --> CI["ビルドと配布の設定を10に変える"]
CI --> DEP["配布する"]
DEP --> CHK{"8を使うアプリが残っているか"}
CHK -->|"残っていない"| DEL["古いランタイムを削除"]
CHK -->|"残っている"| KEEP["削除しない"]
図11: 古いランタイムは、使うアプリが残っていないと確かめてから削除する。
.NET 8 のランタイムを PC から消すのは、棚卸しでそのランタイムを使うアプリが残っていないと確かめてからにします。フレームワーク依存のアプリは、必要なランタイムが見つからないと起動しません13。Visual Studio では、サポートが終わったコンポーネントを削除する設定で .NET 8 と .NET 9 の部品を片付けられます2。
期限に間に合わないアプリ
Microsoft の .NET のサポートポリシーには、Windows のような有償の延長セキュリティ更新(ESU)は書かれていません1。11月10日に間に合わないアプリは、更新が届かない状態で動かすことになります。.NET 10 へ移すまでの選択肢はアプリの配布のしかたと、誰が作ったアプリかで決まります。
flowchart TB
accTitle: 期限に間に合わないアプリの扱い
accDescr: 期限に間に合わないアプリのうち、自社開発のフレームワーク依存のアプリはRollForwardで.NET 10のランタイムを使わせて試験し、自社開発の自己完結型のアプリは.NET 10で発行し直すしかなく、他社製のアプリは提供元に.NET 10への対応を確かめることを示す。
LATE["期限に間に合わない"] --> OWN_FDD["自社開発 フレームワーク依存"]
LATE --> OWN_SC["自社開発 自己完結型"]
LATE --> VENDOR["他社製"]
OWN_FDD --> RF["RollForwardで10のランタイムを使う"]
OWN_SC --> REPUB["10で発行し直す"]
VENDOR --> ASK["提供元に10対応を確かめる"]
図12: 間に合わないアプリの選択肢は、配布のしかたと作った会社で決まる。
RollForward で .NET 10 のランタイムを使う
フレームワーク依存のアプリは、RollForward の既定値の Minor では、同じメジャーバージョンのランタイムがなければ起動しません。RollForward の設定を変えると、.NET 8 向けに作ったアプリを .NET 10 のランタイムで動かせます13。設定はプロジェクトファイルの RollForward プロパティで行い、ビルドすると runtimeconfig.json の rollForward に書き出されます。
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<RollForward>Major</RollForward>
</PropertyGroup>
Major は指定したメジャーバージョン(この例では 8)が入っていないときだけ、入っている中で次に新しいメジャーバージョンを使います。LatestMajor は、8 が入っていても、入っている中でいちばん新しいメジャーバージョンを使います13。
flowchart TB
accTitle: RollForwardの値で選ばれるランタイム
accDescr: .NET 8向けのアプリでは、既定のMinorは8のランタイムがなければ起動せず、Majorは8がなければ次に新しいメジャーバージョンを使い、LatestMajorは8があっても入っている中で最も新しいメジャーバージョンを使うことを示す。
APP[".NET 8向けのアプリ"] --> MINOR["Minor 既定"]
APP --> MAJOR["Major"]
APP --> LATEST["LatestMajor"]
MINOR --> R8["8がなければ起動しない"]
MAJOR --> NEXT["8がなければ次のメジャー"]
LATEST --> NEWEST["常にいちばん新しいメジャー"]
図13: 既定のMinorはメジャーバージョンをまたがず、MajorとLatestMajorはまたぐ。
Major では、9 のランタイムが残っていると 10 ではなく 9 で動きます。10 で動かすには、その PC から 8 と 9 のランタイムを消します。同じ PC に、まだ 8 や 9 を必要とするアプリがあるなら、そのランタイムは消せません。その場合は LatestMajor を使えますが、あとで新しいメジャーバージョンのランタイムを入れたときに、試験していないバージョンで動き始めます。
flowchart TB
accTitle: Majorを使ったときに選ばれるランタイム
accDescr: RollForwardをMajorにした.NET 8向けのアプリは、9のランタイムが残っていれば9で動き、8と9を消せば10で動き、8や9を必要とするほかのアプリがあって消せないときはLatestMajorを使えるが、あとで入れた新しいメジャーバージョンで動き始めることを示す。
APP["Majorにした8向けのアプリ"] --> Q{"8と9のランタイムを消せるか"}
Q -->|"消せる"| R10["10で動く"]
Q -->|"9が残る"| R9["9で動く"]
Q -->|"ほかのアプリが必要"| LM["LatestMajorを使う"]
LM -.-> RISK["新しいメジャーで動き始める"]
図14: Majorで10を使わせるには、8と9のランタイムを消しておく。
この方法で入れ替わるのは、共有のランタイムだけです。アプリに同梱した 8.x の NuGet パッケージ(EF Core 8 など)は古いまま残り、その修正は届きません。共有のランタイムで変わった動作は当たるので17、設定を変えたら、.NET 10 へ上げるときと同じ試験をします。.NET 10 向けにビルドし直せば、コンパイル時に分かる問題も先に見つけられます。そのため、RollForward は .NET 10 向けに作り直したアプリを配るまでのつなぎとして使います。
runtimeconfig.json は利用者も書き換えられ、環境変数 DOTNET_ROLL_FORWARD でも同じ設定ができます13。環境変数を PC 全体に設定すると、その PC で動くすべてのフレームワーク依存のアプリに効きます。自社のアプリでは、プロジェクトファイルで設定してビルドし直すほうが、どのアプリの設定を変えたかを追えます。
自己完結型と他社製のアプリ
自己完結型のアプリは、発行したときにランタイムが決まるので、RollForward は効きません13。.NET 10 で発行し直す以外に、新しいランタイムで動かす方法はありません。ランタイムを同梱しているので、利用者の PC に .NET 10 のランタイムを入れる手間はかかりません。
他社製のアプリについて、Microsoft は提供元に .NET 10 を対象にしたバージョンがあるかを確かめるよう勧めています2。他社製のアプリの runtimeconfig.json を自分で書き換えると、提供元が試験していない組み合わせになります。提供元の案内なしには書き換えず、対応するバージョンが出る時期を確かめます。保守契約が切れていて提供元に頼れない場合は、「保守契約が切れた業務アプリをどうするか」の判断表も使えます。
アプリごとの対応表
棚卸しで作った一覧の各行に、次の表の対応を当てはめます。
| アプリ | 期限までにすること | 間に合わないとき |
|---|---|---|
| 自社開発、フレームワーク依存 | .NET 10 へ上げ、PC に .NET 10 のランタイムを入れて配る | RollForward で .NET 10 のランタイムを使わせ、試験してから配る(同梱のパッケージは古いまま) |
| 自社開発、自己完結型 | .NET 10 で発行し直して配る | 発行し直すまで更新は届かない |
| 他社製 | 提供元に .NET 10 に対応したバージョンがあるかを確かめる | 提供元の案内なしに設定を書き換えない |
| .NET Framework 4.8 / 4.8.1 | 今回の期限の対象外 | ― |
Windows Server 2016 の上で .NET のアプリを動かしているなら、OS の延長サポートが2027年1月12日に終わることにも備えます。サーバーの移行の進め方は「Windows Server 2016のサポート終了に備える」にまとめています。
関連記事
- .NET Frameworkから.NETへの移行前チェックリスト
- Windowsアプリ配布方式の選び方 - MSI/MSIX/ClickOnce/xcopy/独自更新
- Windowsアプリの1ファイル配布 - シングルバイナリとOS依存の限界
- .NET Generic HostとBackgroundServiceをデスクトップアプリで使う理由
- テストのないレガシー業務アプリに安全に手を入れる
- Windows Server 2016のサポート終了に備える
- 保守契約が切れた業務アプリをどうするか
参考リンク
-
Microsoft, .NET and .NET Core Support Policy. .NET 8、9、10 の公開日とサポート終了日、LTS と STS の期間、メンテナンス期間が最後の6か月であること。 ↩ ↩2 ↩3 ↩4
-
.NET Blog, .NET 8 and .NET 9 will reach End of Support on November 10, 2026. 終了後に提供されなくなるもの、11月10日に最後の更新が出る可能性、.NET 10 への移行の勧め、他社製アプリの提供元への確認、Visual Studio のサポート切れのコンポーネントの削除。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, EF Core releases and planning. EF Core 8、9、10 のサポート終了日。 ↩
-
.NET Blog, .NET STS releases supported for 24 months. STS の期間を .NET 9 から24か月に延ばし、.NET 9 の終了日が2026年11月10日になったこと。 ↩
-
Microsoft Learn, Microsoft .NET Framework - Microsoft Lifecycle. .NET Framework がコンポーネントのライフサイクルポリシーに従うこと、各バージョンの終了日。 ↩ ↩2
-
Microsoft Learn, Check installed .NET versions on Windows, Linux, and macOS.
dotnet --list-runtimesの出力と、インストール先のフォルダー。 ↩ ↩2 ↩3 -
Microsoft Learn, Install .NET on Windows. ランタイムの種類、Microsoft Update による更新とサーバーでの扱い、SDK のバージョンごとに必要な Visual Studio のバージョン。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, dotnet command.
--list-runtimesが実行したdotnetと同じアーキテクチャのランタイムだけを表示することと、.NET 10 以降の--arch。 ↩ -
dotnet/sdk, Runtime Configuration Files.
runtimeconfig.jsonのframeworkとframeworksが、フレームワーク依存のアプリを示すこと。 ↩ -
.NET Source Browser, GenerateRuntimeConfigurationFiles.cs. 自己完結型のアプリでは、フレームワークを
includedFrameworksに書き出すこと。 ↩ -
Microsoft Learn, Create a single file for application deployment.
runtimeconfig.jsonとdeps.jsonが1ファイルに含まれること。 ↩ -
Microsoft Learn, dotnet package list command.
--outdated、--vulnerable、--include-transitiveと、.NET 10 で加わった書き方。 ↩ -
Microsoft Learn, Select which .NET version to use. フレームワーク依存のアプリのランタイムの選び方、RollForward の値と設定方法、自己完結型のアプリのランタイムが発行時に決まること。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7
-
.NET Blog, .NET Core 2.1, 3.1, and .NET 5.0 updates are coming to Microsoft Update. クライアントの Windows で Microsoft Update から .NET の更新を受け取るには、「Receive updates for other Microsoft products when you update Windows」を有効にする必要があること。 ↩
-
Microsoft Learn, Upgrade to a new .NET version.
TargetFrameworkの変更、global.json、AnalysisLevel、CI とホスティング環境の更新。 ↩ ↩2 ↩3 ↩4 ↩5 -
Microsoft Learn, Breaking change: ‘dotnet restore’ audits transitive packages. .NET 10 を対象にしたプロジェクトで間接参照のパッケージも監査されることと、その対処。 ↩ ↩2
-
Microsoft Learn, Breaking changes in .NET 10. .NET 10 の破壊的変更の分野別の一覧。 ↩ ↩2 ↩3
-
Microsoft Learn, Breaking change - Empty ColumnDefinitions and RowDefinitions are disallowed. ↩
-
Microsoft Learn, Breaking change: System.Drawing OutOfMemoryException changed to ExternalException. ↩ ↩2
-
Microsoft Learn, Breaking change: BackgroundService runs all of ExecuteAsync as a Task. ↩ ↩2
-
Microsoft Learn, Breaking change - Single-file apps no longer look for native libraries in executable directory. ↩
-
Microsoft Learn, .NET Upgrade Assistant Overview. Upgrade Assistant が非推奨になったことと、GitHub Copilot のモダン化のチャットエージェントが含まれる Visual Studio のバージョン。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
WinForms / WPFアプリのCI/CD実践 ── GitHub Actionsでビルドから署名・配布まで自動化する
WinForms / WPFアプリのCI/CDをGitHub Actionsで組む実務ガイド。windows-latestでのビルド+テストの最小YAML、タグ駆動のバージョン採番、signtoolによる署名の組み込み、MSI/MSIX/ClickOnce/xcopy別のC...
Windowsアプリのタスクトレイ常駐とトースト通知 ── NotifyIconの落とし穴とAppNotificationの選び方
業務Windowsアプリのタスクトレイ常駐とトースト通知の実装を整理します。NotifyIconの正しい使い方、Explorer再起動時の再登録、トーストAPI3種の選定判断表、通知が届かないケースまで解説します。
WinForms/WPFアプリにEntra ID認証を組み込む ── MSAL.NETとWAMブローカーの実務構成
WinForms/WPFデスクトップアプリにEntra ID認証を組み込む手順を整理します。パブリッククライアントの考え方、アプリ登録、MSAL.NETのAcquireTokenSilent、WAMブローカー、トークンキャッシュの永続化まで解説します。
WindowsデスクトップアプリのUI自動テスト ── UI Automationの仕組みとFlaUIで作る壊れにくいテスト
WinForms/WPFアプリのUI自動テストを、Windows UI Automationの仕組みから整理します。FlaUIによる最小実装、AutomationId設計と条件待機で壊れにくくする方法、CI無人実行の罠まで実務目線で解説します。
Windowsアプリ 外注・受託開発を依頼する前に整理したいこと
Windowsアプリの外注・受託開発を依頼する前に、既存ソフト改修、装置連携、COM/ActiveX、配布・更新、保守の整理ポイントを解説します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
UI スレッド / タイマーテーマ
WPF / WinForms、UI スレッド、async/await、タイマー設計を整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
既存Windowsソフトの改修・保守
.NET 8や.NET 9で動いている社内の業務アプリを棚卸しし、.NET 10へ上げる順番と試験の進め方を、実際の構成に合わせて一緒に整理できます。
技術相談・設計レビュー
フレームワーク依存と自己完結型のどちらで配っているか、ロールフォワードで一時的にしのぐか、すぐに.NET 10へ上げるかは、アプリごとの配布方法と試験の手間で決まるので、技術相談・設計レビューとして扱いやすい題材です。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- .NET 8と.NET 9のサポートはいつ終わりますか?
- どちらも2026年11月10日に終わります。.NET 8はLTS、.NET 9はSTSですが、STSのサポート期間が.NET 9から24か月に延びたため、同じ日に終わります。終了後もアプリは動きますが、セキュリティ更新、不具合の修正、技術サポートは提供されません。
- .NET Framework 4.8で作ったアプリも影響を受けますか?
- 受けません。.NET Frameworkは.NET 8や.NET 9とは別の製品で、Windowsのコンポーネントとしてサポートされます。Microsoftのライフサイクルのページでは、.NET Framework 4.8と4.8.1に終了日が設定されていません。
- 移行先はどのバージョンにすればよいですか?
- Microsoftは.NET 10への移行を勧めています。.NET 10はLTSで、2028年11月14日までサポートされます。Visual Studioで開発する場合、.NET 10のSDKにはVisual Studio 2026のバージョン18.0以降が必要です。
- 期限までに移行できないアプリは、.NET 10のランタイムで動かせますか?
- フレームワーク依存で配っているアプリなら、RollForwardの設定で新しいメジャーバージョンのランタイムを使わせることができます。ただし入れ替わるのは共有のランタイムだけで、アプリに同梱した8.xのパッケージは古いまま残ります。共有のランタイムの動作の変更も当たるので、動作を確かめる試験が必要です。自己完結型で配っているアプリにはこの設定が効かず、.NET 10で発行し直す必要があります。