Wednesday, December 24, 2008

ADO.Net Entity Framework – Assembly Not Found Exception

Allow me to share with you the resolution for one of those simple things that should take a few minutes to resolve but ends up taking 3 days.

I’m using the ADO.Net Entity Framework within Code Toaster, my template-based code generation tool, to retrieve and store statement completion metadata to a SQLite database. SQLite newly supports the Entity Framework Designer from within Visual Studio.Net 2005 and 2008, and all that works wondrously.

But when I ran my code in the debugger my entity context object’s constructor threw an “Unable to load System.Drawing, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a” exception. Oddly enough, the version number was for the .Net 1.0 version of System.Drawing. Code Toaster is 100% .Net 3.5 code (or so I thought), which means the version number should have read 2.0.0.0 (.Net 3.5 is really .Net 2.0 plus some extras, like WCF and WPF).

I enabled .Net Framework source stepping (an awesome new feature in VS.Net 2008 SP1), and stepped through the actual .Net Framework source code to try and figure out why .Net felt it needed to load the 1.0 version of System.Drawing when establishing a connection to SQLite.

image

Enabling .Net Framework source stepping

As it turned out, .Net was trying to load lots of assemblies! It appeared as though it was traversing through every assembly I was referencing, as well as every assembly those assemblies referenced, recursively! Dude.

I cranked open Reflector and examined every assembly I had explicitly referenced. Sure enough, an assembly from Actipro Software was referencing System.Drawing, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. The next question was – why was the .Net Entity Framework doing this?

After some more Googling and soul searching, I discovered precisely why. When you add an .edmx model to your project, an Entity Framework connection string is automagically added to your app.config (or web.config, as the case may be). Upon closer inspection, one realizes that this connection string is not like others you may have seen before.

For one, it includes a metadata section, which looks something like this:

metadata=res://*/IntellicacheModel.csdl|res://*/IntellicacheModel.ssdl|res://*/IntellicacheModel.msl

The metadata section is a map that tells .Net where to find these three resources. res://*/ means “search all the assemblies you can find, and don’t stop until you’ve either thrown an exception or found what you’re looking for.”

I replaced the asterisk with the name of the correct assembly (the one whose project that contained the .edmx model; you can also verify by inspecting your assembly in Reflector for these three resources), and it worked! Eureka!

I suppose if I had simply read the documentation first I could have saved myself some trouble.