Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading assembly at runtime fails when I copy the DLL after program startup

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.

like image 695
Slauma Avatar asked Dec 19 '10 14:12

Slauma


People also ask

Can not load file or assembly?

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.

When assembly will load on AppDomain?

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.

What is the method to load assembly given its file name and its path?

LoadFrom(String) Loads an assembly given its file name or path.


2 Answers

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.

like image 103
Hans Passant Avatar answered Oct 20 '22 07:10

Hans Passant


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);
    }
}
like image 40
Ran Avatar answered Oct 20 '22 09:10

Ran