I am trying to find a way to compile assemblies at runtime and load them. Basic intention is to store them in a database not on the disc. So I wrote some code but saw an interesting situation. Here is my code:
//SumLib
namespace SumLib
{
public class SumClass
{
public static int Sum(int a, int b)
{
return a + b;
}
}
}
// Console app
class Program
{
public static void AssemblyLoadEvent(object sender, AssemblyLoadEventArgs args)
{
object[] tt = { 3, 6 };
Type typ = args.LoadedAssembly.GetType("SumLib.SumClass");
MethodInfo minfo = typ.GetMethod("Sum");
int x = (int)minfo.Invoke(null, tt);
Console.WriteLine(x);
}
static void Main(string[] args)
{
AppDomain apd = AppDomain.CreateDomain("newdomain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
apd.AssemblyLoad += new AssemblyLoadEventHandler(AssemblyLoadEvent);
FileStream fs = new FileStream("Sumlib.dll", FileMode.Open);
byte[] asbyte = new byte[fs.Length];
fs.Read(asbyte, 0, asbyte.Length);
fs.Close();
fs.Dispose();
// File.Delete("Sumlib.dll");
apd.Load(asbyte);
Console.ReadLine();
}
}
The code runs perfectly with the delete line is commented out, If I uncomment it, the application domain loads the assembly, AssemblyLoadEvent()
method runs, I see a number 9 on the console, but when the method is over apd.Load()
throws an error : "Could not load file or assembly." which is perfectly reasonable.
The question is: how can AssemblyLoadEvent()
method run without the assembly file on the disc?
If the method somehow runs with the help of raw binary data then is there any way that appdomain finishes the Load()
method succesfully?
So you are trying to load an assembly from a byte[] and call a method. I do not recommend the way you did (working with the AssemblyLoad event), since it will be called for every dependencies.
@Jester is right about loading an assembly using Load() from a parent domain. To correct this, I suggest to use a wrapper class like this:
// Console app
class Program
{
public class AssemblyLoader : MarshalByRefObject
{
public void LoadAndCall(byte[] binary)
{
Assembly loadedAssembly = AppDomain.CurrentDomain.Load(binary);
object[] tt = { 3, 6 };
Type typ = loadedAssembly.GetType("SumLib.SumClass");
MethodInfo minfo = typ.GetMethod("Sum", BindingFlags.Static | BindingFlags.Public);
int x = (int)minfo.Invoke(null, tt);
Console.WriteLine(x);
}
}
static void Main()
{
AppDomain apd = AppDomain.CreateDomain("newdomain", AppDomain.CurrentDomain.Evidence, AppDomain.CurrentDomain.SetupInformation);
FileStream fs = new FileStream("Sumlib.dll", FileMode.Open);
byte[] asbyte = new byte[fs.Length];
fs.Read(asbyte, 0, asbyte.Length);
fs.Close();
fs.Dispose();
File.Delete("Sumlib.dll");
AssemblyLoader loader = (AssemblyLoader)apd.CreateInstanceAndUnwrap(typeof(AssemblyLoader).Assembly.FullName, typeof(AssemblyLoader).FullName);
loader.LoadAndCall(asbyte);
Console.ReadLine();
}
}