MS_NuGetMSB3247 - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki
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)] を "詳細" にセットする。
- Visual Studio の場合
-
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ターゲットの出力を見れば、
「どのアセンブリが、どこから、どの版で来たか」が辿れる。
-
以下からダウンロードできる。
-
以下のように使用する(net, netstd, netcore 等で利用可能)。
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 ファイルの、
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>※ 上記の「マップし直してください。」のバージョンを設定する。
-
手順
- (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" ノードに、次のバインド リダイレクトを追加します
- 参考
- 自動生成されたバインディング リダイレクトを有効または無効にする
https://learn.microsoft.com/ja-jp/dotnet/framework/configure-apps/how-to-enable-and-disable-automatic-binding-redirection
- 自動生成されたバインディング リダイレクトを有効または無効にする
補足(
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 パッケージを上位プロジェクトから上書きインストールすれば良さそう。 -
参考
- dependencies - Adding a bindingRedirect to a .Net Standard library - Stack Overflow
https://stackoverflow.com/questions/46111749/adding-a-bindingredirect-to-a-net-standard-library
- dependencies - Adding a bindingRedirect to a .Net Standard library - Stack Overflow
補足(.NET Core 以降でこの問題が減った理由/最新化): 原文の
「バインディング リダイレクトが無い」は正しく、
そもそも必要が無くなったというのが正確な理解である。
.NET Framework .NET Core / .NET バインドの規則 完全一致(厳密名) より新しい版で満たしてよい 解決の根拠 GAC + bindingRedirectdeps.json版の統一 人が bindingRedirectを書く復元時に NuGet が統一 対応する診断 MSB3247 NU1605(downgrade)等 【.NET Framework】 復元 → 版はバラバラのまま bin に 1 つだけ配置 → 実行時に不整合 → bindingRedirect で辻褄を合わせる 【.NET Core 以降】 復元の時点で「最も高い最小バージョン」に統一される → 不整合が起きない(起きるなら NU1605 でエラーになる)MSB3277(原文が挙げているもの)は
MSB3247 の .NET Core 版にあたる警告で、
対処も原文の通り**「新しい方に揃える」**で正しい。<!-- 上位プロジェクトで明示的に版を引き上げる --> <PackageReference Include="System.Text.Json" Version="8.0.5" />この構造的な改善は、.NET Coreへの移行 の
実務上の大きな動機の一つである
(bindingRedirectの保守から解放される)。
-
警告 : 同じ依存アセンブリの異なるバージョン間での競合が見つかりました。
https://learn.microsoft.com/ja-jp/visualstudio/msbuild/errors/msb3247 -
警告:MSB3277が出た時の対処法メモ - Qiita
https://qiita.com/hahifu/items/8dba20cd06fb0c3a9fa7 -
.net - Resolving MSB3247 - Found conflicts between different versions of the same dependent assembly - Stack Overflow
https://stackoverflow.com/questions/1871073/resolving-msb3247-found-conflicts-between-different-versions-of-the-same-depen -
Code rant: AsmSpy: A little tool to help fix assembly version conflicts
http://mikehadlow.blogspot.com/2011/02/asmspy-little-tool-to-help-fix-assembly.html
- アセンブリの統合を再配置する
https://learn.microsoft.com/ja-jp/dotnet/framework/configure-apps/redirect-assembly-versions - 依存関係の解決(NuGet)
https://learn.microsoft.com/ja-jp/nuget/concepts/dependency-resolution
Tags: 移行, .NET開発, デプロイ, デバッグ, NuGet