I am trying to load an assembly (dll) into an AppDomain and call an entry point. (essentially bootstrap a package into an Azure environment) I have been following this SO article (How do I create an application domain and run my application in it?) and I think I am doing it right, but I'm having some issues.
I have used several articles on here to get me as far as I am, but I keep running into a FileNotFoundException
as described in Unable to load executing assembly into new AppDomain, FileNotFoundException. My problem is that solution doesn't work. The assembly I am trying to execute exists in a different location. So ApplicationBase
needs to be the folder of the assembly I am trying to execute.
var otherType = typeof(BootstrapProxy);
var domaininfo = new AppDomainSetup
{
ConfigurationFile = executingAssembly + ".config",
ApplicationBase = _root
};
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
_domain = AppDomain.CreateDomain(_type.ToString(), adevidence, domaininfo);
_domain.AssemblyResolve += (sender, args) =>
{
var lookupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (lookupPath == null) return null;
var assemblyname = new AssemblyName(args.Name).Name;
var assemblyFileName = Path.Combine(lookupPath, assemblyname + ".dll");
var assembly = Assembly.LoadFrom(assemblyFileName);
return assembly;
};
var proxy = _domain.CreateInstanceAndUnwrap(otherType.Assembly.FullName, otherType.FullName) as BootstrapProxy;
The last line throws the exception and the AssemblyResolve event never fires off (as determined by placing a breakpoint on the var lookupPath
line.
I have also tried the AppDomain.CurrentDomain.AssemblyResolve
event with the same handler as above with no luck. I have also tried creating the same handler inside the BootstrapProxy
class.
I think I am doing this properly but make note of the first paragraph, so if I'm completely off base, I'm not averse to doing things a different way.
UPDATE:
I have changed the code around to forcibly load the assemblies into the new appdomain and still have issues.
var otherType = typeof(BootstrapProxy);
var domaininfo = new AppDomainSetup
{
ConfigurationFile = executingAssembly + ".config",
ApplicationBase = _root
};
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
_domain = AppDomain.CreateDomain(_type.ToString(), adevidence, domaininfo);
var deps = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var dep in deps)
{
var lookupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (lookupPath == null) continue;
var assemblyname = new AssemblyName(dep.Name).Name;
var assemblyFileName = Path.Combine(lookupPath, assemblyname + ".dll");
if (File.Exists(assemblyFileName))
_domain.Load(File.ReadAllBytes(assemblyFileName));
}
_domain.Load(File.ReadAllBytes(Assembly.GetExecutingAssembly().Location));
var sl = _domain.GetAssemblies().ToArray();
var proxy = _domain.CreateInstanceAndUnwrap(otherType.Assembly.FullName, otherType.FullName) as BootstrapProxy;
sl
shows that all the dlls, including the one referenced in the FileNotFoundException
are loaded in the new appdomain.
public class BootstrapProxy : MarshalByRefObject
{
public void Main()
{
Console.WriteLine("Magic happened.");
}
}
UPDATE 2:
I Changed it around to this:
var deps = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
foreach (var dep in deps)
{
var lookupPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (lookupPath == null) continue;
var assemblyname = new AssemblyName(dep.Name).Name;
var assemblyFileName = Path.Combine(lookupPath, assemblyname + ".dll");
if (File.Exists(assemblyFileName))
File.Copy(assemblyFileName, Path.Combine(_root, assemblyname + ".dll"));
}
File.Copy(Assembly.GetExecutingAssembly().Location, Path.Combine(_root, Path.GetFileName(Assembly.GetExecutingAssembly().Location)));
var otherType = typeof(BootstrapProxy);
var domaininfo = new AppDomainSetup
{
ConfigurationFile = executingAssembly + ".config",
ApplicationBase = _root
};
Evidence adevidence = AppDomain.CurrentDomain.Evidence;
_domain = AppDomain.CreateDomain(_type.ToString(), adevidence, domaininfo);
var proxy = _domain.CreateInstanceAndUnwrap(otherType.Assembly.FullName, otherType.FullName) as BootstrapProxy;
if (proxy != null)
{
proxy.Main();
}
This method of copying the assembly and its references to the ApplicationBase of the new AppDomain is not ideal, as there are a few common references and I could end up with version conflicts and other issues.