dotnet formatを使用し、Visual Studioの「ドキュメントのフォーマット」(Ctrl+K, Ctrl+D)相当の整形をソリューション単位で一括適用するWPFツール。
.sln/.slnxを読み込み、プロジェクト単位でチェックボックスから対象を選択- 選択したプロジェクトごとに
dotnet format <csproj>を実行 .editorconfigの設定(スペース・インデントに加え、改行位置などのNew Line系設定を含む)を完全に反映- 実行ログ(時刻・プロジェクト・状態・変更ファイル数)と進捗バー(プロジェクト単位)を表示
- 処理中のキャンセルに対応
- Windows
- .NET SDK(
dotnetコマンドにPATHが通っていること。dotnet formatはSDK同梱) - 対象プロジェクトが事前に復元(restore)済みであること。このツールは
dotnet format --no-restoreで実行するため、packages.config形式のレガシー.NET Frameworkプロジェクトなどdotnet restoreに対応しない形式でも問題なく動作するが、逆に一度もビルド/復元していないプロジェクトでは依存関係が解決できずエラーになる場合がある。事前にVisual Studioで一度開く/ビルドしておくこと。
dotnet build src/FormatFixer.Roslyn.csproj
dotnet run --project src/FormatFixer.Roslyn.csproj
- 「ソリューションを開く」から対象の
.sln/.slnxを選択する - 左側のプロジェクト一覧から整形対象を選択する(既定で全選択)
- 「フォーマット実行」を押す
- 右側のログでプロジェクトごとの成功/エラー、変更ファイル数を確認する
以前のバージョンはMicrosoft.CodeAnalysis.Formatting.Formatter(公開API)を直接呼び出し、ファイル単位でログを出していた。しかし公開Formatterは.editorconfigの改行系オプション(csharp_new_line_before_open_braceなど)を解釈できない制約がある(dotnet/roslyn#40913)。これはVSの「ドキュメントのフォーマット」が使う内部専用フォーマッターでのみ解釈されるためで、.editorconfigの書き方では回避できない。
dotnet formatはこの内部フォーマッターと同じ仕組みで.editorconfigを完全に解釈するため、正確な整形結果を得るにはdotnet formatを呼び出す方式に切り替える必要があった。dotnet formatはプロジェクト単位でしか進捗・結果を明確に扱えないため、ログの粒度もファイル単位からプロジェクト単位に変わっている。
ソリューション読み込み(プロジェクト一覧表示)にはMSBuildWorkspaceを使用しており、起動時に「MSBuildの自動検出に失敗しました」と表示される場合、Visual Studio / .NET SDKのインストール状態を確認したうえで、環境変数FORMATFIXER_MSBUILD_PATHにMSBuildのbinフォルダーを指定してください。
setx FORMATFIXER_MSBUILD_PATH "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\amd64"
(パスは環境によって異なる。ビルドエラーのログに表示されるMSBuildのパスをそのまま使うとよい)
.NET SDK 10.0.200 と Visual Studio 2026(18.x)の組み合わせで、Roslyn の MSBuildWorkspace 経由の処理全般が
System.TypeInitializationException: The type initializer for 'Microsoft.Build.Shared.XMakeElements' threw an exception.
で失敗する既知の回帰が報告されている(dotnet/sdk#53383、dotnet/roslyn#82931、PR #83477で修正)。
dotnet --versionでSDKを確認し、10.0.200であれば10.0.201以降に更新すること。この更新は、dotnet format自体が同じ不具合の影響を受けないようにするためにも必要(dotnet formatもMSBuildWorkspaceベースで実装されている)。
複数のSDKが混在する環境ではglobal.jsonでバージョンを固定すると安定する。
App.xamlはWPF SDKの慣例でApplicationDefinitionとして自動認識されMainが自動生成されるため、App.xaml.csはWPF標準の自動生成Mainを使わず、MSBuildLocator.RegisterDefaults()を最初に呼び出すカスタムMainをエントリポイントにしている。csproj側でApp.xamlを明示的にPageへ変更し、自動生成Mainとの重複(CS0111)を回避している。- MSBuildの自動検出(
MSBuildLocator.QueryVisualStudioInstances())が失敗する環境向けに、環境変数FORMATFIXER_MSBUILD_PATHによる明示的なパス指定をフォールバックとして用意している。 .slnx(XML形式ソリューション)のネイティブ対応は Roslyn 5.0.0 以降で追加されたため、Microsoft.CodeAnalysis.CSharp.Workspaces/Microsoft.CodeAnalysis.Workspaces.MSBuildを5.6.0に固定している。MSBuildWorkspace.OpenSolutionAsyncはファイル拡張子から自動判別するため、呼び出し側のコード変更は不要。Microsoft.CodeAnalysis.Workspaces.MSBuildが推移的に参照するMicrosoft.Build/Microsoft.Build.Framework/Microsoft.Build.Tasks.Core/Microsoft.Build.Utilities.Coreは、ExcludeAssets="runtime"+PrivateAssets="all"を明示指定し、出力ディレクトリにコピーされないようにしている(Microsoft.Build.LocatorのMSBL001チェック対応)。実行時のMSBuildは常にMSBuildLocatorが検出したVS/.NET SDKのものを使う。- フォーマット処理自体は
Formatter.FormatAsyncを使わず、dotnet format <csprojパス> --no-restore --verbosity diagnosticをProcessで起動している(理由は上記「なぜプロジェクト単位のログなのか」を参照)。--no-restoreを付けないとdotnet formatが実行前にNuGet復元を試み、packages.config形式のレガシープロジェクトでRestore operation failed.となるため必須。標準出力からFormatted code fileの出現回数を数えて変更ファイル数として表示している。この文字列パターンはdotnet formatのバージョンによって変わる可能性があるため、カウントが0でも実際には変更されている場合がある(その場合はエラーではなく単に件数表示が不正確なだけ)。 dotnet formatはMSBuildWorkspaceを内部的に使用するため、.NET SDK側のバージョンによっては上記のXMakeElements不具合の影響を受ける可能性がある。プロジェクト一覧読み込みとフォーマット実行は別プロセス(前者はこのアプリ内、後者はdotnetサブプロセス)なので、症状が出る場合はどちらの段階かログで切り分けること。