環境・前提
- ASP.NET MVC 5(Coreではない、.NET Framework)
- VB.NET
- Entity Framework 6 + EntityFramework6.Npgsql
- NpgsqlはWeb.configで設定している。
ソリューション構成
Webプロジェクト(メインプロジェクト)
↓参照
BusinessLogicプロジェクト
↓参照
Entityプロジェクト
↓参照
EF6+Npgsql
障害内容
Webプロジェクトでは直接使用していないEF6+Npgsqlへの参照設定があった為、参照を削除したところ、ビルドは通るのに、MyDbContextクラスのコンストラクタでSystem.InvalidOperationException の実行時例外が発生するようになった。
発生した例外
System.InvalidOperationException: 'The Entity Framework provider type 'Npgsql.NpgsqlServices, EntityFramework6.Npgsql' registered in the application config file for the ADO.NET provider with invariant name 'Npgsql' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.'
発生箇所:
Public Sub new()
MyBase.New("name=MyDbContext") 'ここで例外発生
End Sub
原因および検討事項
- EntityFramework6.Npgsql.dllがASP.NETサイトのbinフォルダに配置されなくなっている。
- EntityFramework6.Npgsqlの機能はソースコード上から直接参照するものではなく、Web.configで動的にロードされるものである為、コンパイラがDLLの必要性を判別できず、配置されなかったものと思われる。
- EntityプロジェクトへのEntityFramework6.Npgsql.dllへの参照追加設定はしてあり、ローカルコピー設定もTrueになっているが、それでもbinフォルダに配置されていない。
- Webプロジェクト(メインプロジェクト)へEntityFramework6.Npgsql.dllの参照設定を行えば強制的にbinフォルダにコピーされる模様。
- しかし、WebプロジェクトではEF6は使っていないし、使わせたくもないので、ここへ参照設定を追加するのは避けたい。
解決策
- ソースコード上でEntityFramework6.Npgsql.dllへの参照がハードコーディングされていれば、コンパイラが依存関係を認識してくれるはず。
- 現状、EntityFramework6.Npgsql.dllに最も近いのはEntityプロジェクトなので、そこに上記のダミーコードを挿入すれば良い。
- 本音を言うと、Entityプロジェクト自体も表向きNpgsqlに依存しているわけではない(データプロバイダとしてEF6が背後で動的ロードしているだけ)なので、ここにそんなダミーコードを追加するのも嫌だが、Webプロジェクトに無意味な参照が追加されるよりはマシと判断。
以下のファイルをEntityプロジェクトに追加した。
Module ResolveReferenceToEF6Npgsql
'意味のないコードだが、これを書かないと、コード上に参照がない為DLLがASP.NET環境に配置されない。
Private __hack As Boolean = Npgsql.NpgsqlServices.Instance IsNot Nothing
End Module
C#だとこんな感じになると思われる。
class ResolveReferenceToEF6Npgsql {
// 意味のないコードだが、これを書かないと、コード上に参照がない為DLLがASP.NET環境に配置されない。
private static bool __hack = (Npgsql.NpgsqlServices.Instance != null);
}
結果
WebプロジェクトからEF6+Npgsqlへの参照設定も問題なく削除し、正しく動作することを確認した。
本当は、プロジェクト設定に「このDLLに依存しているので、公開時に絶対に一緒に配置する」というオプションがあればよいと思うが、そういう設定を見つけられなかった。
試したけどダメだったもの一覧。
- Web.configのsystem.web - compilation - assemblies - add に EntityFramework6.Npgsqlを追加
- Web.configのruntime - assemblyBinding - dependentAssembly に EntityFramework6.Npgsql を追加