dotnet-modernize について
既存の .NET コードから、古いフレームワークやパッケージ、API、未導入の慣行を見つけるスキルです。改善点を提案し、アップグレード自体は実行しません。
主な機能
- 01ターゲットフレームワークの確認
- 02非推奨パッケージの指摘
- 03旧式 API パターンの特定
- 04ビルド設定の不足確認
- 05セキュリティとコンプライアンス上の問題の提示
活用シーン
- 01サポート終了したターゲットフレームワークの発見
- 02パッケージ置き換え作業の計画
- 03古いコードパターンの特定
- 04セキュリティと保守上の課題の優先順位付け
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-modernizeインストール後、Claude Code で/dotnet-modernizeを入力して読み込まれたか確認します。
詳細
dotnet-modernize
既存の .NET コードを分析し、モダン化の機会を特定します。古いターゲットフレームワーク、非推奨のパッケージ、置き換えられた API パターン、最新のベストプラクティスの不足を検出します。各検出項目に対して、実行可能な推奨事項を提示します。
対象範囲の境界: このスキルが行うのは、機会の提示のみです。実際の移行パス、ポリフィル戦略、マルチターゲットのガイダンス、段階的なバージョンアップ手順については、[skill:dotnet-version-upgrade] と [skill:dotnet-multi-targeting] を参照してください。
前提条件: 最初に [skill:dotnet-version-detection] を実行して、現在の SDK、TFM、言語バージョンを確認してください。[skill:dotnet-project-analysis] を実行して、ソリューションの構造と依存関係を把握してください。
相互参照:最新のレイアウト規約については [skill:dotnet-project-structure]、非推奨パターンをアナライザーで検出する方法については [skill:dotnet-add-analyzers]、完全にモダン化されたプロジェクトの目標状態については [skill:dotnet-scaffold-project] を参照してください。
モダン化チェックリスト
既存のコードベースをこのチェックリストに沿って確認してください。各セクションでは、確認すべき項目と最新の代替手段を示します。
1. ターゲットフレームワーク
.csproj ファイル(または Directory.Build.props)の <TargetFramework> を確認します。
| 現在の TFM | 状態 | 推奨事項 |
|---|---|---|
net8.0 | LTS — 2026 年 11 月までサポート | net10.0(LTS)へのアップグレードを計画 |
net9.0 | STS — 2026 年 5 月にサポート終了 | 速やかに net10.0 にアップグレード |
net7.0 | サポート終了 | 直ちにアップグレード |
net6.0 | サポート終了 | 直ちにアップグレード |
net5.0 以下 | サポート終了 | 直ちにアップグレード |
netstandard2.0/2.1 | サポート中(ライブラリ互換性) | 幅広い互換性のためにマルチターゲットにする場合は維持 |
netcoreapp3.1 | サポート終了 | 直ちにアップグレード |
.NET Framework 4.x | レガシー | 移行の実現可能性を評価 |
すべてのプロジェクトをスキャンするには:
# Find all TFMs in the solution
find . -name "*.csproj" -exec grep -h "TargetFramework" {} \; | sort -u
# Check Directory.Build.props
grep "TargetFramework" Directory.Build.props 2>/dev/null
2. 非推奨または置き換えられたパッケージ
置き換えられたパッケージがないか、Directory.Packages.props(または各 .csproj ファイル)をスキャンします。
| 非推奨パッケージ | 置き換え先 | 以降 |
|---|---|---|
Microsoft.Extensions.Http.Polly | Microsoft.Extensions.Http.Resilience | .NET 8 |
Newtonsoft.Json(新規プロジェクト) | System.Text.Json | .NET Core 3.0 以降 |
Microsoft.AspNetCore.Mvc.NewtonsoftJson | 組み込みの STJ | .NET Core 3.0 以降 |
Swashbuckle.AspNetCore | ドキュメント生成には組み込みの OpenAPI(Microsoft.AspNetCore.OpenApi)を使用。Swagger UI、フィルター、コード生成を使用する場合は Swashbuckle を維持 | .NET 9 |
NSwag.AspNetCore | ドキュメント生成には組み込みの OpenAPI を使用。クライアント生成や Swagger UI の機能を使用する場合は NSwag を維持 | .NET 9 |
Microsoft.Extensions.Logging.Log4Net.AspNetCore | 組み込みのロギングと Serilog または OpenTelemetry | .NET Core 2.0 以降 |
Microsoft.AspNetCore.Authentication.JwtBearer(明示的な NuGet パッケージ) | 明示的な PackageReference を削除 — Microsoft.AspNetCore.App 共有フレームワークに含まれています | .NET Core 3.0 以降 |
System.Data.SqlClient | Microsoft.Data.SqlClient | .NET Core 3.0 以降 |
Microsoft.Azure.Storage.* | Azure.Storage.* | 2020 年以降 |
WindowsAzure.Storage | Azure.Storage.Blobs / Azure.Storage.Queues | 2020 年以降 |
Microsoft.Azure.ServiceBus | Azure.Messaging.ServiceBus | 2020 年以降 |
Microsoft.Azure.EventHubs | Azure.Messaging.EventHubs | 2020 年以降 |
EntityFramework(EF6) | Microsoft.EntityFrameworkCore | .NET Core 1.0 以降 |
RestSharp(古いバージョン) | HttpClient + System.Text.Json | .NET Core 以降 |
AutoMapper | 手動マッピングまたはソース生成マッパー | 推奨 |
非推奨パッケージをスキャンするには:
# List all package references
grep -rh "PackageVersion\|PackageReference" \
Directory.Packages.props $(find . -name "*.csproj") 2>/dev/null | \
grep -i "Include=" | sort -u
Newtonsoft.Json に関する注意: カスタムコンバーターや JObject 操作など、Newtonsoft.Json を広範囲に使用している既存プロジェクトでは、直ちに移行してもメリットがない場合があります。検出対象としてフラグを立てたうえで、移行コストを評価してください。
3. 置き換えられた API パターン
最新の代替手段があるコードパターンを探します。
Startup.cs / Program.cs パターン
旧(.NET 6 より前):
public class Startup
{
public void ConfigureServices(IServiceCollection services) { }
public void Configure(IApplicationBuilder app) { }
}
最新(最小ホスティング):
var builder = WebApplication.CreateBuilder(args);
// ConfigureServices equivalent
var app = builder.Build();
// Configure equivalent
app.Run();
HttpClient の登録
旧:
services.AddHttpClient<MyService>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddTransientHttpErrorPolicy(p => p.WaitAndRetryAsync(3, _ => TimeSpan.FromMilliseconds(300)));
最新(Microsoft.Extensions.Resilience を使用):
services.AddHttpClient<MyService>(client =>
{
client.BaseAddress = new Uri("https://api.example.com");
})
.AddStandardResilienceHandler();
同期 I/O
検出対象: File.ReadAllText、Stream.Read、Async 接尾辞のない HttpClient。
最新: async バリアントを使用します。File.ReadAllTextAsync、Stream.ReadAsync、await httpClient.GetAsync() などです。
ホットパスでの文字列連結
検出対象: ログ記録やループ内での文字列連結(+)または String.Format。
最新: LoggerMessage ソースジェネレーターを使用した文字列補間、または StringBuilder を使用します。
レガシーなコレクションパターン
検出対象: Hashtable、ArrayList、非ジェネリックコレクション。
最新: Dictionary<TKey, TValue>、List<T> などのジェネリックコレクションを使用します。
ILogger パターン
旧:
_logger.LogInformation("Processing order {OrderId}", orderId);
最新(高パフォーマンス):
[LoggerMessage(Level = LogLevel.Information, Message = "Processing order {OrderId}")]
static partial void LogProcessingOrder(ILogger logger, string orderId);
4. 最新のビルド構成の不足
推奨されるビルド基盤が不足していないか確認します。
| 不足項目 | 確認方法 | 推奨事項 |
|---|---|---|
| Central Package Management | Directory.Packages.props がない | [skill:dotnet-project-structure] を参照してください |
| Directory.Build.props | プロパティが複数の .csproj ファイルに分散している | 共通プロパティを一元化します |
| .editorconfig | リポジトリのルートに .editorconfig がない | [skill:dotnet-project-structure] を参照してください |
| global.json | SDK の固定がない | 再現可能なビルドのために追加します |
| NuGet の監査 | NuGetAudit プロパティがない | Directory.Build.props で有効にします |
| ロックファイル | RestorePackagesWithLockFile がない | 復元を決定論的にするために有効にします |
| パッケージソースマッピング | nuget.config に packageSourceMapping がない | サプライチェーンのセキュリティのために追加します |
| アナライザー | AnalysisLevel または EnforceCodeStyleInBuild がない | [skill:dotnet-add-analyzers] を参照してください |
| SourceLink | SourceLink パッケージの参照がない | デバッガーでソースへ移動できるように追加します |
| Nullable 参照型 | <Nullable> が有効になっていない | グローバルに有効にします |
| .slnx | .NET 9+ SDK で .sln を使用している | dotnet sln migrate で移行します |
5. 非推奨の C# 言語パターン
| 古いパターン | 最新の置き換え | 言語バージョン |
|---|---|---|
case を使用する switch ステートメント | switch 式 | C# 8 |
null != x / x != null によるチェック | x is not null | C# 9 |
型が明らかな場合の new ClassName() | ターゲット型指定の new() | C# 9 |
| ブロックスコープの名前空間 | ファイルスコープの名前空間 | C# 10 |
明示的なコンストラクターを持つ record class | 位置指定パラメーターを持つ record | C# 10 |
| 複数行文字列の手動連結 | raw 文字列リテラル("""...""") | C# 11 |
INumber<T> の明示的なインターフェイス呼び出し | ジェネリック数学インターフェイス | C# 11 |
[Flags] 列挙型の手動チェック | 改良された列挙型のパターンマッチング | C# 11+ |
| 自然型を持たないラムダ式 | 自然関数型 | C# 10+ |
ValueTask の手動ラップ | ConfigureAwait パターンを使った Task / ValueTask | C# 全般 |
| 手動で実装したプライマリコンストラクタークラス | class / struct のプライマリコンストラクター | C# 12 |
複数の if / else if による型チェック | リストパターンを使った型の switch | C# 11+ |
params T[] | params ReadOnlySpan<T>、params コレクション | C# 13 |
object を使ったロック | System.Threading.Lock | C# 13 |
6. セキュリティとコンプライアンス
| 問題 | 検出方法 | 修正方法 |
|---|---|---|
| 既知の脆弱性 | dotnet list package --vulnerable | 影響を受けるパッケージを更新します |
| 非推奨のパッケージ | dotnet list package --deprecated | 後継パッケージに置き換えます |
| 古いパッケージ | dotnet list package --outdated | 更新を評価します |
| HTTPS リダイレクトの不足 | app.UseHttpsRedirection() がない | パイプラインに追加します |
| HSTS の不足 | app.UseHsts() がない | 本番環境向けに追加します |
| ハードコードされたシークレット | appsettings.json 内の接続文字列 | User Secrets または Key Vault を使用します |
# Run all NuGet audits
dotnet list package --vulnerable --include-transitive
dotnet list package --deprecated
dotnet list package --outdated
最新化スキャンの実行
チェック項目を組み合わせ、体系的にスキャンします。
# 1. Check TFMs
echo "=== Target Frameworks ==="
find . -name "*.csproj" -exec grep -Hl "TargetFramework" {} \; | while read f; do
echo "$f: $(grep -o '<TargetFramework[s]*>[^<]*' "$f" | head -1)"
done
# 2. Check for deprecated packages
echo "=== Package Audit ==="
dotnet list package --deprecated 2>/dev/null
dotnet list package --vulnerable --include-transitive 2>/dev/null
# 3. Check build infrastructure
echo "=== Build Infrastructure ==="
test -f Directory.Build.props && echo "OK: Directory.Build.props" || echo "MISSING: Directory.Build.props"
test -f Directory.Packages.props && echo "OK: Directory.Packages.props (CPM)" || echo "MISSING: Directory.Packages.props"
test -f .editorconfig && echo "OK: .editorconfig" || echo "MISSING: .editorconfig"
test -f global.json && echo "OK: global.json" || echo "MISSING: global.json"
test -f nuget.config && echo "OK: nuget.config" || echo "MISSING: nuget.config"
# 4. Check for old patterns in code
echo "=== Code Patterns ==="
grep -rl "class Startup" --include="*.cs" . 2>/dev/null && echo "FOUND: Legacy Startup.cs pattern"
grep -rl "Microsoft.Extensions.Http.Polly" --include="*.csproj" --include="*.props" . 2>/dev/null && echo "FOUND: Deprecated Polly package"
grep -rl "Swashbuckle" --include="*.csproj" --include="*.props" . 2>/dev/null && echo "FOUND: Swashbuckle (consider built-in OpenAPI for .NET 9+)"
grep -rl "System.Data.SqlClient" --include="*.csproj" --include="*.props" . 2>/dev/null && echo "FOUND: System.Data.SqlClient (use Microsoft.Data.SqlClient)"
モダナイゼーションの優先順位付け
すべてのモダナイゼーションが同じように緊急というわけではありません。影響度に基づいて優先順位を付けてください。
- セキュリティ -- 脆弱性のあるパッケージ、サポート終了の TFM(セキュリティパッチが提供されない)
- サポート性 -- 上流でのメンテナンスが行われていない非推奨のパッケージ
- パフォーマンス -- パフォーマンスに大きな影響を与えるパターン(同期処理から非同期処理への変換、ホットパスでのレガシーコレクション)
- 開発者エクスペリエンス -- ビルドインフラストラクチャ(CPM、アナライザー、editorconfig)によって日々のワークフローが改善されます
- コードスタイル -- 言語パターンの更新は優先度が最も低いものの、長期的には認知負荷を軽減します
次のステップ
このスキルはモダナイゼーションの機会を示します。アップグレードの実行については、以下を参照してください。
- TFM のバージョンアップグレードと移行パス -- [skill:dotnet-version-upgrade]
- マルチターゲティング戦略 -- [skill:dotnet-multi-targeting]
- バージョン間のサポートに対応するポリフィルパッケージ -- [skill:dotnet-multi-targeting]
- 不足しているビルドインフラストラクチャの追加 -- [skill:dotnet-project-structure]、[skill:dotnet-scaffold-project]
- アナライザーの設定 -- [skill:dotnet-add-analyzers]
- CI/CD の追加 -- [skill:dotnet-add-ci]