Weird behavior when mixing loading of assemblies using Assembly.LoadFrom and Assembly.Load
I have encountered a weird behavior when loading assemblies with Assembly.LoadFrom and later on with Assembly.Load.
I am loading an assembly using Assembly.LoadFrom, where the assembly is located in a folder which is not the execution folder.
Later on in my test code when I try to load once again this assembly with Assembly.Load, the load fails with a System.IO.FileNotFoundException (“Could not load file or assembly…”) despite the fact that the assembly is already loaded. The load fails both with the strong name and the non-strong name (the original reason for loading once again this assembly is a usage of a BinaryFormatter).
However, in case the assembly is located in the execution folder the later load succeeds in both cases, with the strong name and the non-strong name. In this case you can see that two identical assemblies are loaded from two different locations.
A simple code sample that recreates this problem –
Assembly assembly1 = Assembly.LoadFrom(@"C:\a.dll");
// Loading with a strong-name fails Assembly assembly2 = Assembly.Load(@"a, Version=1.0.0.0, Culture=neutral, PublicKeyToken=14986c3f172d1c2c");
// Also loading with a non-strong fails Assembly assembly3 = Assembly.Load(@"a");
- Any explanation why the CLR ignores the already loaded assembly?
- Any idea how can I alleviate this problem?
Thanks.
-
That's not weird. As per the documentation, loading with Load and LoadFrom will place the assemblies in different contexts. This might help.
- Any explanation why the CLR ignores the already loaded assembly?
Because they're in a different context.
- Any idea how can I alleviate this problem?
Load from the same context, or help the CLR find the assembly, perhaps by attaching a handler to
AppDomain.AssemblyResolve.HTH, Kent
Alternative
If the location you are loading assemblies from is a subfolder under AppDomain.BaseDirectory you can simply add an entry to your App.config:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="bin;bin2\subbin;bin3"/> </assemblyBinding> </runtime> </configuration> -
@Kent Boogart: That appears to be the correct explanation. For a full explanation, Suzanne Cook has this blog post which elaborates a little more than the original one you posted: http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx
Following is code leveraging AppDomain.AssemblyResolve -
// register to listen to all assembly resolving attempts: AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler); // Check whether the desired assembly is already loaded private static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { AssemblyName assemblyName = assembly.GetName(); string desiredAssmebly = args.Name; if (assemblyName.FullName == desiredAssmebly) { return assembly; } } // Failed to find the desired assembly return null; }
0 comments:
Post a Comment