0
votes

I've been looking at an issue related to unit testing and managed/native interop via C++/CLI. The details aren't important so I won't fill them in unless asked, but the situation can be distilled as follows:

Two assemblies, call them Lib and Dep, exist in the same directory, call it D. Lib depends on Dep via an assembly reference. We are running in an application that lives in a different, unrelated directory. The application creates a new AppDomain with ApplicationBase set to directory D, loads the Lib assembly, and tries to construct a type in it via reflection.

As part of Lib's module constructor we transition into the default AppDomain and load the referenced assembly Dep. Because the default AppDomain's ApplicationBase is NOT directory D, Dep cannot be resolved, a FileNotFoundException is thrown, and loading the Lib assembly fails.

This all makes sense -- convoluted as it may be, we tried to load an assembly that's not on the assembly resolution path for the current AppDomain, and failed.

BUT if I run this whole process in the default AppDomain instead of creating a new AppDomain, there is no failure. Even through directory D is not the ApplicationBase, the Lib assembly is loaded and the code instantiating one of its classes runs correctly. The module constructor code should still be run in the default AppDomain although it does not need to transition to it.

It seems to me that the second case should fail just like the first one. What's different about the assembly reference resolution process between these two cases?

1
Use Fuslogvw.exe to get insight. Log all binds.Hans Passant
Great suggestion, thanks for pointing me at that utility. I will check it out and report back.rationull
I've been unable to get anything useful out of the Fusion log. There are no log entries at all for the Dep assembly in either the success or failure cases. The log entry for the Lib assembly has some content in the success case but in the failure case it seems to fail out pretty early in the process, probably because the actual load failed. Although I expected to see at least something for the failing assembly itself, which could've provided some insight.rationull

1 Answers

0
votes

OK, I found what I was missing before via a more complete reading of the MSDN page "How the Runtime Locates Assemblies" than I'd done before. The very last section, "Other Locations Probed" outlines that when resolving references for an assembly being loaded, the loaded assembly's location is taken as a hint for where the referenced assembly can be found.

Based on the behavior I'm seeing I think we can extrapolate that the hint information is AppDomain-specific, such that the hint is not taken into account outside the AppDomain that triggered the original assembly load.

I verified this with my test project -- if the referenced assembly does not switch into the default AppDomain then it loads correctly. So this is not default AppDomain special behavior, it's general AppDomain constrained behavior.