Unload DLL after loading with Assembly.LoadFrom() - c#

In my project I am loading a DLL using reflection and Assembly.LoadFrom(). This is a small DLL that is occasionally recompiled (from the source) dynamically during application execution.
Is there a way to unload the loaded DLL from the application so that I can reload it? I've tried reloading it, but I get an error:
file in use by another program

If the application that has the file open is a custom app, then you could modify it to load the DLL into another AppDomain. When you want to reload it, simply tear down that AppDomain and load the new DLL into the new AppDomain. I'd have a look at MEF (which does this) to see whether this might support your use case.

You can't. You have to kill the program. There is no way to unload an assembly in .Net.

Read these:
http://blogs.msdn.com/b/jasonz/archive/2004/05/31/145105.aspx
http://blogs.msdn.com/b/suzcook/archive/2003/07/08/unloading-an-assembly.aspx

Related

C# Dynamically Load An Assembly And Use It And Then Unload it

I'm working on a plugin where the shell dll invokes methods in several other function dlls. Because we want to replace these function dlls during updating, the shell dll has to dynamically load those dll, and when updating, dynamically unload them.
I can do the load and unload part with AppDomain, but I can't find any resources about how to create an instance of a type in the loaded dll and invoke method on it. I'd be very much appreciate it if anyone can elaborate on this...
Thanks!

How to dynamically load and unload an F# dll into an C# project?

I understand how to load an F# dll into a project. But I would like to be able to load specific parts of them dynamically and without a big performance hit from the dll being purely functional.
To unload an application domain
There is no way to unload an individual assembly without unloading all of the application domains that contain it. Use the Unload method from AppDomain to unload the application domains. For more information, see How to: Unload an Application Domain.
Taken from https://msdn.microsoft.com/en-us/library/ms173101.aspx
The idea will be to initialize a new application domain for the F# library, then drop it after you're done using it. I think you're going to have to make sure you compile the F# lib as a Strong-Named assembly and add it to the GAC to accomplish this, but I'm not positive.

Loading C# DLL to C++/CLI - dependencies directory

I wrote a dll c++/cli library which uses my other c# dll library. C++/cli library works fine when I've got c# dll in the same folder as application which calls it. This library will be finally loaded to many applications and a C# dll must not be copied into directory with application. It has to be in the same folder as c++/cli library, but in that cases I've got System.IO.FileNotFoundException.
My suggestion is to load c# library manually or to change path where f.ex. firefox is looking for dependencies, but I tried with LoadLibrary() and Assembly::LoadFrom() methods to force loading from right directory. Of course I added directory path with dll to system PATH.
I work on VS2010.
You don't change the default directory where an application will look for dlls.
At design time put your dll in some well know location, the one you are going to deploy to. Add a reference to it, make sure it's set to Don't copy ever, otherwise it will end up in the bin folder. You have to do this otherwise it won't compile.
When you deploy, you'll need one package to deploy common dlls, and one for each application. Careful you don't create your own version of dll hell, if appA needs an older or new version of the common dll, compared to AppB
Add an AppDomain.AssemblyResolve event to main (for windows app). At run time the event handler will get fired when you reference a type in your dll, and the assembly has not yet been loaded.
In there you load it from the well known location. That usually in config, or in a relative path.
E.g.
AllMyApps
CommonDLLS
MyFirstApp
So the path you load the required common dll from would be "..\CommonDlls\MyCommondll.dll".
NB you will want to secure the dlls in some way, otherwise a bad guy might be able to inject their version of one in to your app, which would be bad...
You can use this mechanism to get the dll from a remote server or a database blob as well.
The simplest case is only a few lines of code, just look the event up. Took me about 15 minutes to get this going in a similar scenario.
Not on this machine though, otherwise I'd have pasted in the code.

MSBuild assembly lock

I have a custom MSBuild task(resides in assembly A) to build a custom project type(let's call it 'TestAppContent'). 'A' references another assembly 'B' that is currently under development.
To test 'B', I use a test program, TestApp. TestApp depends on TestAppContent getting build using our custom task.
The problem is that after the task is loaded, 'B' assembly is locked by MSBuild or VisualStudio process as the assembly that contains the task('A') has a reference to it.
As I can't simply 'unload' an assembly and using separated AppDomain doesn't work, how can I stop this lock?
I know that Microsoft XNA can do this as you can supply custom assemblies to the build process and they are released after it so you can rebuilt those custom assemblies.
The only way is to use an AppDomain and activate the Shadow Copy on it. I don't think you can activate shadow copy on current AppDomain, but you can try (see question here)
Or you can manually copy the dll elsewhere and load it (programmatically) so that the original dll will not be loaded and will remain unlocked. But you can't load the same dll twice... so you'll need a separate AppDomain if you want to unload and load a new version (or you restart your program)
EDIT:
You can also use AppDomain.CurrentDomain.AssemblyResolve to intercept when you program try to load a dll. There you can copy it elsewhere and load this copy.
I think it won't help you that much since you're trying to achieve it automatically but one manual way to achieve this i found out was using sysinternals ProcessExplorer to kill the specific process using the dll. But killing doesn't seem to harm VS2013, which makes this is a workaround without the need to restart MSVS.
In this case my Visual Studio process instantiated an MSBuild instance which previously created the DesignLibrary assembly - now being locked, which the project SomeLibrary uses right within the build only. At this point it is not possible to rebuild the DesignLibrary assembly without killing the MSBuild task holding the lock.
I would like to have the MSBuild.exe checking during the build if it tries to rebuild a file created by itself, or maybe visual studio intervening this messy situation. Just another thought: Maybe it might be possible to inspect the process tree and kill the process automatically, like i did manually. A very hacky workaround ;)
One way I usually solve this is by having two solutions. The first builds the Tasks and then I hook it up to launch devenv.exe to load the second .sln when I press F5.
The second solution consumes the task built in the first causing it to be loaded into the second devenv.exe process. When you stop debugging the second Visual Studio will close and the assembly with the build task will be released.

release Assembly.LoadFrom file handle

I'm trying to get assembly version of an exe in C# with the following code
Assembly asm = Assembly.LoadFrom(address);
return asm.GetName().Version;
it works perfect but if I try to delete the exe after I used this function, it says "Access Denied" since the exe is being used by another process!
is there any Dispose call or something which releases the file handle or any other solution?
There is no way to unload an assembly other than unloading the application domain. See How to: Load and Unload Assemblies:
There is no way to unload an
individual assembly without unloading
all of the application domains that
contain it. Use the Unload method from
AppDomain to unload the application
domains. For more information, see
Unloading an Application Domain.
If you just want to get the version of a file, try using FileVersionInfo.GetVersionInfo.
This issue was dealt with here
How to unload an assembly from the primary appdomain

Categories