The given assembly name or codebase was invalid

Man, spent a few hours tracking down a doozy today.

So we have this application that loads a new AppDomain, sets an explicit cache path and turns on shadow copying. This application originally didn't shadow copy, but we noticed file locking issues when people rebuilt their assemblies (it's an addin-like app) so we turned on shadow copying. Then we noticed that if you ran 'gacutil /ldl', the assemblies we load showed up in there hundreds of times after heavy usage (restarting the app multiple times a day for weeks). Turns out that using Assembly.Load and the file not in the GAC would cause the file to get copied to the download cache. This wouldn't be a big deal, except sometimes an incorrect version of an assembly would be loaded, seemingly at random from the download cache (we would make tons of minor changes visible on their UIs and notice through multiple restarts that different, random versions would get loaded).

So we next provide an explicit cache path that is unique per instance of our running application and clean it up when we're done with it. So naturally where do you put per-user per-instance files on a hard drive when you don't ask the user for permission to save something? In the user's local settings folder, of course! There's no other place you are "guaranteed" to have write access as a full trust application.

So we have a structure like so:

C:\Documents and Settings\{user id}\Local Settings\Application Data\Company\Product\ShadowCopy\{GUID}

Then if you look at how the shadow copying works:

{root}\{application name}\assembly\dl2\1501ae1d\00b21a13_bbc5c501\{file name}

The GUID is used to make sure we have something that is truly unique per application instance. The shadow copy directory structure is out of your control so you're stuck with its length.

Next consider the current "standard" for DLL names: {Company}.{Technology/Product}.{Feature}.dll

Put this all together, in the case of our application at work, and we had file names that were 248 characters long.

Next, put this on a machine running a German Windows OS - which has localized "Documents and Settings" into "Dokumente und Einstellungen" and "Local Settings\Application Data" into "Lokale Einstellungen\Anwendungsdaten" - and we ended up with a file name that was 265 characters long. Throw into the mix variable length user IDs and you could get shorter or longer.

Do you know if a file path of length 265 is legal on all versions of Windows? Supposedly NTFS supports ridiculously large file path lengths, however Explorer and most all Win32 file APIs support file paths up to 255 characters long. Yep, 255 characters long!!!!!!!!!! Any file greater than that will get an error.

What's the specific problem with shadow copying? The application fails to load successfully and will crash with a FileLoadException. Turns out it was with this basic error:
"The given assembly name or codebase, '[Assembly Name]', was invalid." at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Boolean isStringized, Evidence assemblySecurity, Boolean throwOnFileNotFound, Assembly locationHint, StackCrawlMark& stackMark) at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Boolean stringized, Evidence assemblySecurity, StackCrawlMark& stackMark) at System.Reflection.Assembly.InternalLoad(String assemblyString, ...
I had seen this error previously when changing an assembly to be a strong named assembly and not refreshing my application's bindings to it (so it thought it was loading a non-strong named assembly but I threw a strong named one in there). This makes perfect sense so I was surprised to see this error come up in a completely different situation.

Luckily we had the .NET SDK installed so I ran the fusion log viewer (fuslogvw.exe) to see if Fusion was having troubles. The logs basically indicated that the file was found (when the file is not found, it indicates as much) then it was setting up shadow copying, then at that point it got a "Failed" error and no further information.

After trying a few other things I thought maybe I was hitting the file length limit (which I had forgotten about for the first few hours of looking at this bug) so I altered the shadow copy path to be the root C: drive. Lo and behold, the application loaded perfectly and without problems. Turns out it was the 'codebase' portion of the error message that was invalid, because the codebase path was too long for Windows to handle.

Anyway, to get around this, I had to do a "dirty" thing and put the root cache path in C:\Documents and Settings\{user id} directly and not in the Local Settings\Application Data folder. It saves me quite a few characters (and I only needed about 10) and keeps it in a directory where I know the logged on non-administrative user will have priveledges to write to. And I made it configurable if we end up having user with about 60 characters in their username.

Searching Google for this error message barely has any hits of real solutions so I figured I'd put it up here to make sure Google picks it up.

2 comment(s)

ada wrote on January 23, 2008

It's helpfull for me , Thank you !

anonymous wrote on January 23, 2008

Why does every developer start the first sentence in an article, post, or blog "So" I did such and such. Why not just say I did such and such.

So................I did this the other day.