ASP.NET(.NET Framework 4.8)で運用しているサイトが、ある日突然「Could not load file or assembly ‘Microsoft.CSharp, Version=4.0.0.0(または 8.0.0.0)’」で落ちる――そんなトラブルは、原因さえ分かってしまえば比較的シンプルに解決できます。この記事では、なぜ 4.0.0.0 と 8.0.0.0 がぶつかるのか、その仕組みから、実務でそのまま使えるチェックリスト・再発防止策まで、現場目線で詳しく解説します。
現象の整理:突然発生する Microsoft.CSharp の読み込みエラー
まずは、実際に表示されるエラーメッセージを整理しておきます。典型的には、以下のような例外が ASP.NET アプリの起動時や特定画面の表示時に発生します。
Could not load file or assembly 'Microsoft.CSharp, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.
The system cannot find the file specified.
または
Could not load file or assembly 'Microsoft.CSharp, Version=8.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.
The system cannot find the file specified.
スタックトレースの中には Version=4.0.0.0 と Version=8.0.0.0 が混在して表示されることもあり、ログには次のような警告が出ている場合があります。
WRN: Assembly binding logging is turned OFF.
環境としては、次のような構成で起きることが多いでしょう。
| 項目 | 内容の例 |
|---|---|
| OS | Windows Server 2016 / 2019 / 2022 |
| Web サーバー | IIS 10.x |
| アプリ種別 | ASP.NET Web Forms / ASP.NET MVC(.NET Framework 4.8) |
| アセンブリ | Microsoft.CSharp を利用(dynamic キーワードなど) |
「昨日まで普通に動いていたのに、ライブラリやツールを更新したあとから急に落ちる」というパターンが典型的です。
前提知識:ASP.NET と Microsoft.CSharp の関係
.NET Framework 4.x の ASP.NET は Microsoft.CSharp 4.0.0.0 を使う
ASP.NET アプリケーション(.NET Framework 4.8)では、C# の dynamic キーワードや一部のランタイムバインディング機能を使うために Microsoft.CSharp.dll が利用されます。
重要なのは、.NET Framework 4.x 系では アセンブリのバージョンは常に 4.0.0.0 で固定されている、という点です。ファイルバージョンは 4.8.x.x のように変わりますが、アセンブリバージョンは 4.0.0.0 のままです。
| 項目 | .NET Framework 4.8 | .NET 8(参考) |
|---|---|---|
| アセンブリ名 | Microsoft.CSharp | Microsoft.CSharp |
| アセンブリバージョン | 4.0.0.0 | 8.0.0.0 など |
| 配置場所のイメージ | GAC(フレームワーク内蔵) | アプリローカル(.NET 8 ランタイム配下など) |
| 想定ターゲット | .NET Framework アプリ | .NET 8 / ASP.NET Core アプリ |
つまり、.NET Framework 4.8 の ASP.NET アプリで正しく使うべき Microsoft.CSharp は 4.0.0.0 版のみであり、8.0.0.0 版は .NET 8 用です。この 2 つが同じアプリドメイン内で混在すると、アセンブリ バインディングの解決に失敗し、今回のようなエラーになります。
なぜ 4.0.0.0 と 8.0.0.0 の競合が起きるのか
.NET ランタイムは、アセンブリをロードする際に次のような情報をセットで見ています。
- アセンブリ名(Microsoft.CSharp)
- バージョン(4.0.0.0 / 8.0.0.0 など)
- Culture(通常は neutral)
- PublicKeyToken(Microsoft 製なら b03f5f7f11d50a3a)
どこかのライブラリや設定が「Microsoft.CSharp, Version=8.0.0.0」を要求すると、ランタイムは 8.0.0.0 を探しに行きます。しかし、.NET Framework の世界には 8.0.0.0 向けの Microsoft.CSharp は存在しません。結果として、
- 4.0.0.0 を持っているが、8.0.0.0 を要求されているため見つからない
- 逆に、誤って 8.0.0.0 の DLL を bin に置いてしまい、別の箇所で 4.0.0.0 を要求して競合する
といった状況が発生し、アセンブリ バインディングエラーになります。
よくある原因パターン
このエラーを引き起こしやすい、典型的な原因をパターン別に整理します。
| 原因パターン | 具体例 | よくあるきっかけ |
|---|---|---|
| web.config に 8.0.0.0 を直書き | <assemblies> で Version=8.0.0.0 を指定 | 他プロジェクトの設定をコピペ |
| net8.0 向け DLL の混入 | bin に .NET 8 用ライブラリがデプロイされる | パッケージ更新 / CI 設定ミス |
| NuGet と GAC の二重参照 | Microsoft.CSharp を NuGet とフレームワーク両方から参照 | 警告を消すために安易にパッケージ追加 |
| マルチターゲットパッケージの誤利用 | net48 / net8.0 の両方を含むパッケージで net8.0 側 DLL が使われる | ビルド構成やコピー条件のミス |
特に多いのは「web.config に Version=8.0.0.0 を書いてしまった」パターンと、「パッケージ更新後に net8.0 向け DLL が紛れ込んだ」パターンです。
解決方針:4.0.0.0 に統一する
結論から言うと、.NET Framework 4.8 の ASP.NET アプリでは Microsoft.CSharp を 4.0.0.0 に統一するのが正しい解決方針です。NuGet で 8.0.0.0 を導入してはいけませんし、.NET 8 用ライブラリが bin に入っていてもいけません。
ここからは、実務でそのまま使える「上から順に試すチェックリスト」として具体的な手順を解説していきます。
チェックリスト 1:プロジェクト参照を 4.0.0.0 に一本化する
NuGet の Microsoft.CSharp 参照を削除する
.NET Framework アプリでは、本来 Microsoft.CSharp の NuGet パッケージは必要ありません。まずは以下を確認・実施します。
- Visual Studio でプロジェクトを右クリック → [NuGet パッケージの管理]
- [インストール済み] タブから Microsoft.CSharp を探す
- 入っている場合は [アンインストール] を実行
古いプロジェクトでは packages.config 形式になっていることも多いため、ファイルを直接開いて Microsoft.CSharp の記述がないかもチェックすると確実です。
<packages>
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
</packages>
上記のような行があれば削除し、ソリューションを再読み込みします。
フレームワーク参照として Microsoft.CSharp を追加する
もし参照そのものが無くてコンパイルエラーになっている場合は、NuGet ではなく フレームワーク参照として追加します。
- プロジェクトを右クリック → [追加] → [参照]
- [アセンブリ] → [Framework] を選択
- 一覧から Microsoft.CSharp にチェックを付けて OK
これで、GAC にインストールされている Version=4.0.0.0 の Microsoft.CSharp を参照するようになります。
csproj 内の重複参照を確認する
場合によっては、csproj に同じアセンブリへの参照が複数記述されていることがあります。csproj をテキストエディタで開き、Microsoft.CSharp に関する列挙を確認します。
<Reference Include="Microsoft.CSharp" />
似たような行が複数ある場合は、不要なものを削除して一つに整理します。必要以上に SpecificVersion や HintPath を指定するのも、バージョン競合のもとになるので極力避けましょう。
チェックリスト 2:web.config の設定を見直す
<compilation><assemblies> の Version=8.0.0.0 を削除
ASP.NET Web Forms / MVC では、web.config に次のような記述が紛れ込んでいることがあります。
<compilation debug="true" targetFramework="4.8">
<assemblies>
<add assembly="Microsoft.CSharp, Version=8.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
</assemblies>
</compilation>
これは .NET 8 用アセンブリ向けの指定であり、.NET Framework 4.8 では誤りです。丸ごと削除するか、少なくとも Microsoft.CSharp に関する行は削除してください。
必要に応じて bindingRedirect で 4.0.0.0 固定にする
プロジェクトや依存パッケージのどこかが古いバージョンの Microsoft.CSharp を要求している場合は、bindingRedirect で 4.0.0.0 に統一するのが定番の解決策です。
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.CSharp"
publicKeyToken="b03f5f7f11d50a3a"
culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-8.0.0.0"
newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
ポイントは、oldVersion に 8.0.0.0 までを含めてしまうことです。これにより、「8.0.0.0 を要求されたとしても、ランタイムは 4.0.0.0 にマッピングしてロードしようとする」ようになります。
ただし注意点として、もし依存ライブラリが本当に .NET 8 専用の API を使っている場合には、このリダイレクトでは根本解決しません。その場合は、当該ライブラリを net48 / netstandard2.0 など .NET Framework 互換版に置き換える必要があります。
チェックリスト 3:依存パッケージの整合性を回復する
Update-Package -Reinstall で再インストール
パッケージの更新作業中に DLL が中途半端な状態になり、古いファイルが残ったり、別ターゲットの DLL が混ざることは珍しくありません。packages.config プロジェクトの場合は、一度パッケージを「再インストール」すると状況が改善することがあります。
PM> Update-Package -Reinstall
このコマンドは、インストール済みパッケージをもう一度入れ直し、参照と実際の DLL を一致させるためのものです。特に複数人で開発している場合、誰かの環境だけ DLL が不整合になっているケースを解消できます。
NuGet キャッシュのクリア
ローカルの NuGet キャッシュに壊れたパッケージが残っていると、何度インストールしても同じ不具合が再現します。その場合は次のコマンドでキャッシュを一掃します。
nuget locals all -clear
その上で Visual Studio を再起動し、パッケージの再インストールを行ってください。
各ライブラリのターゲットフレームワークを確認する
依存パッケージがどのフレームワークを対象にビルドされているかも重要です。次のようなイメージで整理すると分かりやすくなります。
| ターゲット | .NET Framework 4.8 からの利用可否 | コメント |
|---|---|---|
| net48 | ◎ | .NET Framework 4.8 専用。最も安全。 |
| net472 / net461 など | ◎ | 同じ .NET Framework 系。基本的に問題なし。 |
| netstandard2.0 | ○ | .NET Framework 4.6.1 以降で利用可能。4.8 なら基本 OK。 |
| net8.0 / net7.0 / net6.0 | × | .NET 8/7/6 専用。ASP.NET (.NET Framework) からは利用不可。 |
パッケージがマルチターゲット(net48, net8.0 を両方含む)になっている場合、ビルド設定やコピー条件を誤ると net8.0 側の DLL が bin に入ってしまうことがあります。その結果、Microsoft.CSharp 8.0.0.0 を要求する DLL が紛れ込み、今回のエラーを引き起こします。
チェックリスト 4:クリーン & 再ビルドを徹底する
設定を修正しただけでは、古い DLL が bin に残り続けることがあります。以下の手順で「物理的な掃除」を行うのが安全です。
- Visual Studio を閉じる
- プロジェクト配下の
bin/objフォルダを手動で削除 - Visual Studio を管理者として起動
- ソリューションを開き、[クリーン] → [リビルド] を実行
Web デプロイや CI を使っている場合は、ビルドサーバー側でも同様にクリーンビルドを行い、不要な DLL がデプロイされないようにしてください。
チェックリスト 5:IIS / サーバー側の設定を確認する
.NET Framework 4.8 が正しくインストールされているか
まれですが、サーバー側の .NET Framework インストールが不完全な場合、GAC から Microsoft.CSharp を正しくロードできないことがあります。サーバーで以下の点を確認します。
- 「プログラムと機能」で .NET Framework 4.8 が有効になっているか
- 最新の累積更新プログラムが適用されているか
別の ASP.NET 4.x サンプルアプリを動かしてみて、同様のエラーが出ないか確認するのも有効です。
アプリケーションプールの .NET CLR バージョン
IIS のアプリケーションプール設定で、.NET CLR バージョンが「v4.0」になっていることを確認します。「No Managed Code」になっていると、.NET Framework 4.x アプリは正しく動作しません。
- IIS マネージャーを開く
- 対象のアプリケーションプールを右クリック → [基本設定]
- [.NET CLR バージョン] が v4.0.x になっていることを確認
デプロイ先の bin に 8.0.0.0 が紛れ込んでいないか
サーバー側の bin フォルダ内を確認し、Microsoft.CSharp.dll のプロパティからバージョンをチェックします。アセンブリバージョンが 8.0.0.0 になっているファイルが存在したら要注意です。
その DLL は .NET 8 用のものである可能性が高いため、デプロイ対象から除外するか、適切なバージョン(4.0.0.0)に置き換える必要があります。
チェックリスト 6:Fusion ログ(Fuslogvw)で原因を特定する
WRN: Assembly binding logging is turned OFF とは
ログに表示される
WRN: Assembly binding logging is turned OFF
という警告は、「アセンブリ バインディングの詳細ログ(Fusion ログ)が無効になっている」という意味です。どのパスのどのバージョンを探しにいって失敗したのかを知るには、これを有効にする必要があります。
Fuslogvw.exe の使い方
Fusion ログを確認するには、Fuslogvw.exe(Assembly Binding Log Viewer) を使います。
- Developer Command Prompt for VS などから
Fuslogvw.exeを起動 - メニューから [Settings] を開き、[Log bind failures] を選択
- 必要に応じてログの保存先パスを設定
- ASP.NET アプリでエラーを再現する
- Fuslogvw の一覧にログが出てくるので、該当エントリをダブルクリックして詳細を確認
ログには、次のような情報が含まれます。
- 要求されたアセンブリ名・バージョン(例:Microsoft.CSharp, Version=8.0.0.0)
- どのフォルダを探索したか(bin、GAC など)
- 最終的にどこで失敗したか
これを見れば、「どのライブラリが 8.0.0.0 を要求しているのか」「どのパスに 8.0.0.0 を探しにいっているのか」が一目で分かり、原因の切り分けが一気に進みます。
チェックリスト 7:新規プロジェクトでの切り分け
どうしても原因が特定できない場合は、次のような「最小再現プロジェクト」を作って切り分けるのが有効です。
- Visual Studio で 新規 ASP.NET Web アプリ(.NET Framework 4.8) を作成
- 本番と同じ NuGet パッケージを、ひとつずつ(または小さな単位で)追加
- 各ステップでビルド・実行し、どのパッケージ追加でエラーが出るか確認
エラーが出た時点で「その時に追加したパッケージ群」が怪しい領域です。さらにその中から一つずつ外していくことで、問題のライブラリを特定できます。
実際のトラブルシューティング事例
事例 1:ログ出力ライブラリの更新後にエラー発生
あるプロジェクトでは、ログ出力ライブラリ(仮に Sample.Logging とします)を最新版に更新したところ、IIS 上でアプリが起動しなくなりました。エラーメッセージは Microsoft.CSharp 8.0.0.0 の読み込み失敗です。
調査の結果、このライブラリの最新版は net8.0 のみをターゲットとしたパッケージに変更されており、内部で Microsoft.CSharp 8.0.0.0 を参照していました。これを気付かずに .NET Framework プロジェクトで利用したことが原因でした。
対処として、
- Sample.Logging のバージョンを net48 対応の最終バージョンまで戻す
- web.config の bindingRedirect で Microsoft.CSharp を 4.0.0.0 に統一
- bin/obj を削除してクリーンビルド
を実施した結果、エラーは解消しました。
事例 2:web.config コピペによる Version=8.0.0.0 混入
別のプロジェクトでは、.NET 8 の ASP.NET Core プロジェクトから設定を参考にしているうちに、誤って以下のような記述を web.config に追加してしまいました。
<assemblies>
<add assembly="Microsoft.CSharp, Version=8.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
</assemblies>
この結果、.NET Framework 4.8 の ASP.NET アプリが 8.0.0.0 を要求し始め、IIS 上で起動しなくなりました。Fuslogvw で確認すると、8.0.0.0 を必死に探し回るログが大量に出力されていました。
ここでは単純に上記の行を削除し、bindingRedirect を 4.0.0.0 に設定するだけで解決しました。ついでに NuGet の Update-Package -Reinstall を実行し、DLL の整合性も一緒に整えています。
再発防止のための運用ポイント
パッケージ更新のルールを決める
チーム開発では、「とりあえず最新に更新しておく」という運用は非常に危険です。次のようなルールを決めておくと、今回のようなトラブルを未然に防ぎやすくなります。
- プロジェクトのターゲットフレームワーク(例:net48)を明確に定義する
- パッケージ更新時には、Release Notes と Supported frameworks を必ず確認する
- .NET Framework プロジェクトに .NET 6/7/8 専用パッケージを入れない
- 更新作業は必ずブランチで行い、テスト環境で動作確認してからマージする
.NET Framework プロジェクトと .NET 8 プロジェクトを混在させない
ソリューション内に .NET Framework と .NET 8 のプロジェクトが混在していると、誤って .NET 8 用の設定やパッケージを流用してしまう事故が起きやすくなります。
ソリューションの構成として、
- .NET Framework 用ソリューション
- .NET 6/7/8 用ソリューション
を分ける、あるいはフォルダ構成・命名規則で明確に区別するなど、人的ミスを起こしにくい構造にしておくと良いでしょう。
CI/CD で「誤ったターゲット」を検知する
CI パイプラインに、次のような簡単なチェックを組み込むのも有効です。
binフォルダ内に net8.0 などの文字列を含むパスがないかチェック- Microsoft.CSharp.dll のアセンブリバージョンが 4.0.0.0 以外の場合はビルドを失敗させる
スクリプトや PowerShell を使えば、特定バージョンの DLL が混入していないかを自動で検査できます。
よくある質問(FAQ)
Q. .NET Framework でも Microsoft.CSharp の NuGet を入れていい?
A. 原則として不要ですし、推奨されません。 Microsoft.CSharp は .NET Framework では GAC に標準で含まれており、フレームワーク参照だけで十分です。NuGet 版を追加すると、GAC 版との二重参照やバージョン競合の原因になります。
Q. bindingRedirect で 8.0.0.0 に統一してもいい?
A. やめたほうがよいです。 .NET Framework 4.8 のランタイムは 8.0.0.0 の Microsoft.CSharp を前提としていませんし、そもそも .NET 8 用 DLL は .NET Framework では動かない API に依存している可能性があります。基本方針は「4.0.0.0 に統一」です。
Q. dynamic を使っていないのに Microsoft.CSharp が必要になることはある?
あります。アプリ自身が dynamic を使っていなくても、参照ライブラリの内部で dynamic を利用しているケースがあります。その場合、ライブラリ側の都合で Microsoft.CSharp が必要になり、今回のようなバージョン競合が表面化します。
Q. 「WRN: Assembly binding logging is turned OFF」の警告は無視していい?
A. 原因調査をするなら無視すべきではありません。 この警告は、詳細なバインディングログが取れていないことを示すだけなので、それ自体がエラーというわけではありません。しかし、エラーの真の原因を突き止めるには Fusion ログが非常に有用なので、Fuslogvw でログを有効化してから再現させることをおすすめします。
まとめ:Microsoft.CSharp 4.0.0.0 に揃えて安定運用しよう
今回の「Could not load file or assembly ‘Microsoft.CSharp, Version=4.0.0.0 / 8.0.0.0’」エラーの本質は、.NET Framework 4.8 向け ASP.NET アプリに、.NET 8 向けの設定や DLL が紛れ込んだことによるバージョン競合です。
対策を改めてまとめると、次のようになります。
- Microsoft.CSharp への参照は 4.0.0.0(フレームワーク内蔵)に一本化する
- NuGet での Microsoft.CSharp 追加は原則不要なので、入っていたら削除する
web.configの <assemblies> にある Version=8.0.0.0 の記述は削除する- 必要に応じて bindingRedirect で 0.0.0.0〜8.0.0.0 を 4.0.0.0 にリダイレクトする
- 依存パッケージのターゲットフレームワークを net48 / netstandard2.0 などに揃える
- bin / obj の削除 → クリーンビルド で古い DLL を一掃する
- それでも分からない場合は Fuslogvw(Fusion ログ) でどの DLL が何を要求しているかを特定する
特に、「.NET Framework 向け ASP.NET では、Microsoft.CSharp を NuGet で追加する必要は基本的にない」というポイントを押さえておくと、同種のトラブルを大きく減らせます。運用中の ASP.NET サイトがこのエラーで止まってしまったときは、本記事のチェックリストを上から順に確認してみてください。

コメント