At runtime I load an assembly with
Assembly assembly = Assembly.LoadFrom(@"c:\MyFolder\MyAssembly.dll");
This works if the assembly is in that folder.
If the assembly is NOT in the folder I get an exception of course telling me that the assembly or one of its dependencies could not be found.
I'm catching the exception and display an error message to the user. The program keeps running.
If I copy now the missing assembly to the folder "c:\MyFolder" while the program is still running and trigger the function again which executes the line above I get the same exception - a System.IO.FileNotFoundException - again that the assembly could not be found although the DLL is now in the folder.
If I restart the application it works and the assembly is found. It also works if I start the application and copy the DLL to the folder before I try to load the assembly for the first time after application start.
So the problem seems to be related to the first failed call of Assembly.LoadFrom
.
What can be the reason for this behaviour and what can I do to solve the problem?
Thank you for help in advance!
Edit: One more detail:
I've added a File.Exists
test:
string filename = @"c:\MyFolder\MyAssembly.dll";
bool test = File.Exists(filename);
Assembly assembly = Assembly.LoadFrom(filename);
test
returns true
but Assembly.LoadFrom
throws a FileNotFoundException
.
In summary if you get the "Could not load file or assembly error", this means that either your projects or their references were built with a reference to a specific version of an assembly which is missing from your bin directory or GAC.
If an assembly is loaded into the same AppDomain, then the class can be instantiated in the usual way. But if an assembly is loaded into a different AppDomain then it can be instantiated using reflection. Another way is an interface.
LoadFrom(String) Loads an assembly given its file name or path.
Feature, not a bug. It is a DLL Hell counter-measure. The operative term is 'loading context', search Suzanne Cook's blog for the phrase to learn more about it. In a nutshell, the CLR memorizes previous attempts to load an assembly. First and foremost, it records successful bindings and guarantees that the exact same assembly will be loaded again, even if the disk contents have changed. You can no doubt see the benefit of that, suddenly getting another assembly is almost always disastrous.
The same is true for failed assembly binds. It memorizes those as well, for much the same reason, it will fail them in the future. There is no documented way to reset the loading context that I know of. Assembly.LoadFile() loads assemblies without a loading context. But that causes a whole range of other problems, you really don't want to use it.
In order to bypass the CLR caching of LoadFrom
attempts, you can change your code a little to use the Assembly.Load(byte[] rawAssembly)
overload.
Something like this:
Assembly LoadWithoutCache(string path)
{
using (var fs = new FileStream(path, FileMode.Open))
{
var rawAssembly = new byte[fs.Length];
fs.Read(rawAssembly, 0, rawAssembly.Length);
return Assembly.Load(rawAssembly);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With