AppDomain dependencies across directories
Posted
by
strager
on Stack Overflow
See other posts from Stack Overflow
or by strager
Published on 2010-12-24T14:31:29Z
Indexed on
2010/12/24
15:54 UTC
Read the original article
Hit count: 545
I am creating a plugin system and I am creating one AppDomain per plugin. Each plugin has its own directory with its main assemblies and references. The main assemblies will be loaded by my plugin loader, in addition to my interface assemblies (so the plugin can interact with the application).
Creating the AppDomain:
this.appDomain = AppDomain.CreateDomain("AppDomain", null, new AppDomainSetup
{
ApplicationBase = pluginPath,
PrivateBinPath = pluginPath,
});
Loading the assemblies:
this.appDomain.Load(myInterfaceAssembly.GetName(true));
var assemblies = new List<Assembly>();
foreach (var assemblyName in this.assemblyNames)
{
assemblies.Add(this.appDomain.Load(assemblyName));
}
The format of assemblyName
is the assembly's filename without ".dll".
The problem is that AppDomain.Load(assemblyName)
throws an exception:
Could not load file or assembly '[[assemblyName]], Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
All of the dependencies of [[assemblyName]]
are:
- Inside the directory
pluginPath
, - The
myInterfaceAssembly
which is already loaded, or - In the GAC (e.g. mscorelib).
Clearly I'm not doing something right. I have tried:
- Creating an object using
this.appDomain.CreateInstanceAndUnwrap
inheriting from MarshalByRefObject with aLoadAssembly
method to load the assembly. I get an exception saying that the current assembly (containing the proxy class) could not be loaded (file not found, as above), even if I manually callthis.appDomain.Load(Assembly.GetExecutingAssembly().GetName(true))
. - Attaching an
AssemblyResolve
handler tothis.appDomain
. I'm met with the same exception as in (1), and manually loading doesn't help. Recursively loading assemblies by loading their dependencies into
this.appDomain
first. This doesn't work, but I doubt my code is correct:private static void LoadAssemblyInto(AssemblyName assemblyName, AppDomain appDomain) { var assembly = Assembly.Load(assemblyName); foreach (var referenceName in assembly.GetReferencedAssemblies()) { if (!referenceName.FullName.StartsWith("MyProject")) { continue; } var loadedAssemblies = appDomain.GetAssemblies(); if (loadedAssemblies.Any((asm) => asm.FullName == referenceName.FullName)) { continue; } LoadAssemblyInto(referenceName, appDomain); } appDomain.Load(assembly.GetName(true)); }
How can I load my plugin assembly with its dependencies in that plugin's directory while also loading some assemblies in the current directory?
Note: The assemblies a plugin may (probably will) reference are already loaded in the current domain. This can be shared across domains (performance benefit? simplicity?) if required.
Fusion log:
*** Assembly Binder Log Entry (12/24/2010 @ 10:46:40 AM) ***
The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.
Assembly manager loaded from: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable C:\MyProject\bin\Debug\MyProject.vshost.exe
--- A detailed error log follows.
LOG: Start binding of native image vshost32, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=x86.
WRN: No matching native image found.
LOG: Bind to native image assembly did not succeed. Use IL image.
LOG: IL assembly loaded from C:\MyProject\bin\Debug\MyProject.vshost.exe
© Stack Overflow or respective owner