How to Unload an Assembly from the Primary Appdomain

Unloading the Assembly loaded with Assembly.LoadFrom()

Unfortunately you can not unload an assembly once it is loaded. But you can unload an AppDomain. What you can do is to create a new AppDomain (AppDomain.CreateDomain(...) ), load the assembly into this appdomain to work with it, and then unload the AppDomain when needed. When unloading the AppDomain, all assemblies that have been loaded will be unloaded. (See reference)

To call the garbage collector, you can use

GC.Collect(); // collects all unused memory
GC.WaitForPendingFinalizers(); // wait until GC has finished its work
GC.Collect();

GC calls the finalizers in a background thread, that's why you have to wait and call Collect() again to make sure you deleted everything.

dynamically loading and unloading of c# assembly into appdomain

I found that Assembly.LoadFile(...) will lock the file, even beyond the point of unloading the AppDomain.

My solution is to first load the assembly bytes into memory, and then load it into the AppDomain:

var assemblyBytes = System.IO.File.ReadAllBytes("myassembly.dll");
var assembly = System.Reflection.Assembly.Load(assemblyBytes);

That way the file is never locked and you can delete it, etc.

There's a better answer to a similar question here.

Loading/Unloading assembly in different AppDomain

Try this:

namespace SeperateAppDomainTest
{
class Program
{
static void Main(string[] args)
{
LoadAssembly();
}

public static void LoadAssembly()
{
string pathToDll = Assembly.GetExecutingAssembly().CodeBase;
AppDomainSetup domainSetup = new AppDomainSetup { PrivateBinPath = pathToDll };
var newDomain = AppDomain.CreateDomain("FooBar", null, domainSetup);
ProxyClass c = (ProxyClass)(newDomain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ProxyClass).FullName));
Console.WriteLine(c == null);

Console.ReadKey(true);
}
}

public class ProxyClass : MarshalByRefObject { }

Unload Assembly From App Domain

As a rule of thumb, as soon as you have an Assembly instance, it means that the assembly in question is loaded in the current domain.

Meaning that, when you call the AppDomain.Load method, you load the assembly both in your current domain, and in the new domain. (As you can see in the remarks for that method on MSDN, "This method should be used only to load an assembly into the current application domain.")

EDIT: The previously posted "solution" was removed as it did not actually solve the issue. A working solution was edited into the question by the author.

Load and unload a dll dynamically into my project using AppDomain

You define a GetAssembly method in your proxy domain, which pulls the loaded Assembly into the main domain. This renders the whole concept pointless, because even if you unload the proxy domain, your main domain will be eventually polluted by the loaded assembly.

Instead of returning the assembly just use it inside your proxy domain. If you want to push back some information into the main domain you must pass simple serializable types (or remote objects derived from MarshalByRefObject) so the main domain remains clean.

This is how you should do it:

// This class provides callbacks to the host app domain.
// This is optional, you need only if you want to send back some information
public class DomainHost : MarshalByRefObject
{
// sends any object to the host. The object must be serializable
public void SendDataToMainDomain(object data)
{
Console.WriteLine($"Hmm, some interesting data arrived: {data}");
}

// there is no timeout for host
public override object InitializeLifetimeService() => null;
}

And your proxy should look like this:

class AssemblyLoader : MarshalByRefObject
{
private DomainHost host;

public void Initialize(DomainHost host)
{
// store the remote host here so you will able to use it to send feedbacks
this.host = host;
host.SendData("I am just being initialized.")
}

// of course, if your job has some final result you can have a return value
// and then you don't even may need the DomainHost.
// But do not return any Type from the loaded dll (not mentioning the whole Assembly).
public void DoWork()
{
host.SendData("Work started. Now I will load some dll.");
// TODO: load and use dll
host.SendData(42);

host.SendData("Job finished.")
}
}

Usage:

var domain = AppDomain.CreateDomain("SandboxDomain");
var loader = (AssemblyLoader)domain.CreateInstanceAndUnwrap(typeof(AssemblyLoader).Assembly.FullName, typeod(AssemblyLoader).FullName);

// pass the host to the domain (again, this is optional; just for feedbacks)
loader.Initialize(new DomainHost());

// Start the work.
loader.DoWork();

// At the end, you can unload the domain
AppDomain.Unload(domain);

And finally for the FileNotFoundException itself:

In an AppDomain you can only load assemblies, which reside in the same or a subfolder of the main domain. Use this instead of Environment.CurrentDirectory in the setup object:

var setup = new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
PrivateBinPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
};

If you really want to load an assembly from any location, load it as a byte[]:

var dll = Assembly.Load(File.ReadAllBytes(fullPathToDll));

Unload Assembly or AppDomain after Use (like in Object Browser)

Based on Mathieu Guindon's Comment. I am loading assembly in my ASP.Net Web API and Serializing the assembly content to JSON Array. Later in my client application I am Deserializing the response with the help HttpClient and populating the WinForms TreeView.

Here's how I did. Sample code.

//Action Model
public class ActionModel
{
public string ActionName {get;set;}
public IList<MethodInformation> ActionMethods {get;set;}
}

public class MethodInformation
{
public string MethodName {get;set;}
public IList<ParameterInformation> GetParameters {get;set;}
}

//API
public Object Get(string id)
{
switch(id)
{
case "Assembly1":
Type[] typesInAssembly = Assembly.LoadFrom(pathToAssembly).GetTypes();

List<ActionModel> actionModel = new List<ActionModel>();

for(var t in typesInAssembly)
{
/* add the items to the List actionModel */
}
return actionModel;
}
}

On the client side I am having one more Class which consumes this API and parses the content by Deserializing the JSON Content and display it in treeview.

Now the requirement is met. I can use the same copy of Assembly to show and build which was main requirement. Hope I am doing this correctly.

How can I delete an assembly applied to the class property?

You can't arbitrarily unload an assembly, you must instead unload the AppDomain in which the assembly is loaded (which unloads all assemblies in the AppDomain). If you're not loading it into a separate AppDomain, then the only way to do that would be to shut down the application.

There are various links in this question with details on why this is not supported: How to unload an assembly from the primary AppDomain?



Related Topics



Leave a reply



Submit