Kraviec Kraviec - 1 month ago 15
C# Question

Dynamically load assembly from byte[]

I need to load several assemblies from memory multiple times at runtime. I also need a possibility to reload those assemblies after some changes made to them.

I've tried standard Assembly.Load method and it worked fine until I realized that when I loaded the same assembly again, it appeared twice in

AppDomain.CurrentDomain.GetAssemblies()


which is not what I want to accomplish due to multiple load operations. I know that if I will load DLL from disk it won't load if it's there in unchanged form.

Then I tried with loading DLLs into new AppDomain, but I got problem with dependencies.

Here is simplified scenario:

I have shared DLL, call it AssemblyA, which is referenced by main application.

I have also several DLLs which I want to dynamically load (call them AssemblyB...Z). These DLLs also reference AssemblyA.

My main application, as I mentioned above, references AssemblyA which has abstract class with method implemented by main application(call it LoadAssemblies). This method is used for loading dynamically rest of assemblies via new AppDomain.

Here is the current code of LoadAssemblies (I tried with manually loading dependencies):

public override void LoadAssemblies()
{
AppDomain pluginDomain = AppDomain.CreateDomain("PluginDomain");


foreach (byte[] xmlDLL in listOfDLLS)
{
Assembly reflection = Assembly.ReflectionOnlyLoad(xmlDLL);


foreach (var dependencies in reflection.GetReferencedAssemblies())
{
if (dependencies.Name.Equals("AssemblyA"))
{
Assembly pluginr = Assembly.ReflectionOnlyLoad(AssemblyA);
foreach (var d in pluginr.GetReferencedAssemblies())
pluginDomain.Load(d);
pluginDomain.Load(plugin);
}
else
pluginDomain.Load(dependencies);
}
Assembly assembly = pluginDomain.Load(xmlDLL);
}


The code above is getting error on line

Assembly assembly = pluginDomain.Load(xmlDLL);


saying that it:

could not load assembly or one of its dependencies


Tried also with AssemblyResolver event, but it complains about Serializable, and then when I made it serializable, about type.

PS. Unfortunately I can't save DLLs on disk.

Answer

I found working workaround. The solution is to use:

pluginDomain.SetData("Assembly", DLLinByteArray);
pluginDomain.DoCallBack(CallbackFunction)

whenever I need to do something within custom AppDomain.

For example for loading DLLs from byte array, the CallbackFunction looks like this:

byte[] assemblyToLoad = (byte[])AppDomain.CurrentDomain.GetData("Assembly");
Assembly.Load(assemblyToLoad);

As you can see I use SetData and GetData methods for sending parameter to callback method.

Of course for invoking method from DLL which resides in custom AppDomain I do this inside another CallbackFunction.

Comments