Skip to content

MS_NuGetMSB3247

nishi_74322014 edited this page Sep 1, 2026 · 1 revision

Nuget使用時に「warning MSB3247 Found conflicts between different versions of the same dependent assembly.」が発生

概要

  • NuGet は非常に便利だが、この問題がよく起きるようになった。
  • バインディング リダイレクトによって対応可能。

問題の内容

以下のようなエラーが出た場合の対処。

  • warning MSB3247: 同じ依存アセンブリの異なるバージョン間での競合が見つかりました。
  • warning MSB3247: Found conflicts between different versions of the same dependent assembly.

問題の対策

ビルド出力ログを確認して、バインディング リダイレクトを、設定する。

補足(なぜ「よく起きるようになった」のか): NuGet 普及以前は、
参照するアセンブリを人が選んでいたため、版が揃っていた。
NuGet が推移的依存を自動で引き込むようになった結果、
同じアセンブリの異なる版が同時に要求される状況が常態化した。

あなたのアプリ ──> LibA ──> Newtonsoft.Json 9.0
             └───> LibB ──> Newtonsoft.Json 13.0

  bin\ に置けるのは 1 つだけ(13.0)
    → LibA は 9.0 を要求する
    → .NET Framework は厳密一致を要求 → 実行時に落ちる

MSB3247 は「このままだと実行時に落ちる」という予告である。
警告なのでビルドは通ってしまう点が厄介で、
テストで踏むまで気付かないことが多い。

詳細

バインディング リダイレクトが設定されていない場合、
以下のバージョン不一致のケースでも、競合が報告される。

  • 下位モジュールで、下位バージョンの依存関係モジュールを使用
  • 上位モジュールで、上位バージョンの依存関係モジュールを使用

調査方法

ビルド出力の詳細化

  • ビルド出力のレベルを上げる。

    • Visual Studio の場合
      • [ツール] → [オプション] → [プロジェクトおよびソリューション] → [ビルド/実行] で、
      • [MSBuild プロジェクト ビルドの出力の詳細(V)] を "詳細" にセットする。
  • MSBuild の場合

    • -verbosity(-v) スイッチに
    • level オプションとして「d[etailed]」を指定する。
      • q[uiet]
      • m[inimal]
      • n[ormal]
      • d[etailed]
      • diag[nostic]
  • 以下、"詳細" のビルド出力。

yyyy/MM/dd HH:mm:ss にビルドを開始しました。
ノード 1 上のプロジェクト "XXXX.sln" (既定のターゲット)。
ValidateSolutionConfiguration:
  ソリューション構成 "Debug|Any CPU" をビルドしています。
プロジェクト "XXXX.sln" (1) は、ノード 1 上に "XXXX.csproj" (2) をビルドしています (既定のターゲット)。
ResolveAssemblyReferences:
  競合を解決して警告を消去するために、app.config でアセンブリ "YYYY, Culture=neutral, PublicKeyToken=YYYY" をバージョン "6.9.9.0" [] からバージョン "6.9.11.0" [YYYY.dll] にマップし直してください。
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3247: 同じ依存アセンブリの異なるバージョン間での競合が見つかりました。 [XXXX.csproj]
GenerateTargetFrameworkMonikerAttribute:
すべての出力ファイルが入力ファイルに対して最新なので、ターゲット "GenerateTargetFrameworkMonikerAttribute" を省略します。
CoreCompile:
すべての出力ファイルが入力ファイルに対して最新なので、ターゲット "CoreCompile" を省略します。
_CopyAppConfigFile:
すべての出力ファイルが入力ファイルに対して最新なので、ターゲット "_CopyAppConfigFile" を省略します。
CopyFilesToOutputDirectory:
  XXXX -> XXXX.dll
プロジェクト "XXXX.csproj" (既定のターゲット) のビルドが完了しました。
プロジェクト "XXXX.sln" (既定のターゲット) のビルドが完了しました。

ビルドに成功しました。

"XXXX.sln" (既定のターゲット) (1) -> "XXXX.csproj" (既定のターゲット) (2) -> (ResolveAssemblyReferences ターゲット) -> 
  C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets(1605,5): warning MSB3247: 同じ依存アセンブリの異なるバージョン間での競合が見つかりました。 [XXXX.csproj]

    1 個の警告
    0 エラー

経過時間 00:00:00.nn

※ 伏せているけど、上記は、バージョン番号からして MySQL。
このように、どの依存アセンブリでバージョン間の競合が起きているかも確認できる。

補足(詳細度は上げすぎない): detailed で足りる。
diagnostic にすると出力が数十 MB になり、
かえって原因を見失う。

ログをファイルに落として検索するのが実務的である。

msbuild Foo.sln -v:d -fl -flp:logfile=build.log
Select-String -Path build.log -Pattern "MSB3247|マップし直して|Consider app.config"

バイナリ ログ-bl)を使うと、さらに調べやすい。

msbuild Foo.sln -bl:build.binlog
# MSBuild Structured Log Viewer(GUI)で開いて検索・絞り込みができる

ResolveAssemblyReferences ターゲットの出力を見れば、
「どのアセンブリが、どこから、どの版で来たか」が辿れる。

ツール(AsmSpy)を使用

AsmSpy C:\...\bin

補足: AsmSpy は現在も有効で、dotnet tool としても入る。

dotnet tool install -g asmspy
asmspy bin\Release\net48 --all --nonsystem

出力の読み方: 同じアセンブリ名に対して
複数の「Reference: x.y.z.w」が並び、
そのうち 1 つだけが実際に配置されている
——という形で表示される。
赤くなっている行が、解決できていない参照である。

対策方法

依存アセンブリのバージョンを一致させる

  • この方法は、下位モジュールが NuGet パッケージだったりすると適用できない。
  • このような場合、以下のバインディング リダイレクトの方法を適用する。

補足(現在はこちらを先に試す): 「バージョンを一致させる」方は
根本的な解決であり、現在は先に検討すべきである。

# 競合しているパッケージを、最新の同一版に揃える
Update-Package Newtonsoft.Json -Reinstall

「下位モジュールが NuGet パッケージだと適用できない」という原文の
指摘は、推移的依存の版を直接指定できなかった時代の話である。
PackageReference 方式では、
上位で明示的に参照すれば版を引き上げられる
(最も高い最小バージョンが選ばれるため)。

<!-- 推移的にしか来ていないものを、明示的に固定する -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

さらに、中央パッケージ管理を使えば
リポジトリ全体で版を統一できる
NuGetパッケージのプレリリース版 の補足を参照)。

config ファイルにバインディング リダイレクト セクションを追加する。

以下のように、*.config ファイルの、
configuration -> runtime セクション以下に
バインディング リダイレクトを設定する。

<dependentAssembly>
  <assemblyIdentity name="YYYY" publicKeyToken="YYYY" culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-6.9.11.0" newVersion="6.9.11.0" />
</dependentAssembly>

※ 上記の「マップし直してください。」のバージョンを設定する。

Project ファイルに自動バインディング リダイレクトを設定する。

  • 手順

    • (1)Project ファイルに以下を追加する。
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  • (2)警告を確認する。
重大度レベル	コード	説明	プロジェクト	ファイル	行	抑制状態
警告 "XXXXXXXXXX" の異なるバージョン間で、解決できない競合が見つかりました。
これらの参照上の競合は、ログの詳細度が詳細に設定されている場合にビルド ログにリストされます。
  • (3)対象アセンブリの dependentAssembly を削除する。
<dependentAssembly>
  <assemblyIdentity name="XXXXXXXXXX" publicKeyToken="XXXXXXXXXX" culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-n.0.0.0" newVersion="n.0.0.0" />
</dependentAssembly>
  • (4)以下の警告をダブルクリックしダイアログで「はい」を押下すると、
    自動的に必要なバインドを追加できる。
同じ依存アセンブリの異なるバージョン間で競合が見つかりました。
Visual Studio では、この警告をダブルクリックする (または選択して Enter キーを押す) ことで、この競合を修正できます。
または、アプリケーション構成ファイル内の "runtime" ノードに、次のバインド リダイレクトを追加します

補足(AutoGenerateBindingRedirects の注意点): 便利だが、
効かない場面があるので押さえておく。

プロジェクト種別 自動生成
EXE(コンソール、WinForms、WPF) App.config に出力される)
クラス ライブラリ ×.dll.config は実行時に読まれない)
単体テスト GenerateBindingRedirectsOutputType が要る)
ASP.NET(Web) ×web.config は自動生成されない)
<!-- テスト プロジェクトで有効にする場合 -->
<PropertyGroup>
  <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
  <GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>

ASP.NET では web.config に手で書くか、
パッケージ マネージャー コンソールで生成する。

Add-BindingRedirect

また、生成されるのは bin\App.exe.config であり、
App.config 自体は書き換わらない点にも注意する
(ソース管理には反映されない)。

.NET Core の場合

  • .NET Core には、バインディング リダイレクトが無い。

  • 特に、Microsoft.AspNetCore.App 使用時などで、MSB3277 が出るので、
    ログを確認し、問題を起こしているバージョン間の新しい方(若しくは最新版)
    の NuGet パッケージを上位プロジェクトから上書きインストールすれば良さそう。

  • 参考

補足(.NET Core 以降でこの問題が減った理由/最新化): 原文の
「バインディング リダイレクトが無い」は正しく、
そもそも必要が無くなったというのが正確な理解である。

.NET Framework .NET Core / .NET
バインドの規則 完全一致(厳密名) より新しい版で満たしてよい
解決の根拠 GAC + bindingRedirect deps.json
版の統一 人が bindingRedirect を書く 復元時に NuGet が統一
対応する診断 MSB3247 NU1605downgrade)等
【.NET Framework】
   復元 → 版はバラバラのまま bin に 1 つだけ配置 → 実行時に不整合
      → bindingRedirect で辻褄を合わせる

【.NET Core 以降】
   復元の時点で「最も高い最小バージョン」に統一される
      → 不整合が起きない(起きるなら NU1605 でエラーになる)

MSB3277(原文が挙げているもの)は
MSB3247 の .NET Core 版にあたる警告で、
対処も原文の通り**「新しい方に揃える」**で正しい。

<!-- 上位プロジェクトで明示的に版を引き上げる -->
<PackageReference Include="System.Text.Json" Version="8.0.5" />

この構造的な改善は、.NET Coreへの移行
実務上の大きな動機の一つ
である
bindingRedirect の保守から解放される)。

参考

Microsoft Learn


Tags: 移行, .NET開発, デプロイ, デバッグ, NuGet

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally