Ich muss eine Methode in einer zur Laufzeit geladenen Assembly ausführen. Nun möchte ich diese geladenen Assemblys nach dem Methodenaufruf entladen. Ich weiß, dass ich eine neue AppDomain brauche, damit ich die Bibliotheken entladen kann. Aber hier tritt das Problem auf.
Die zu ladenden Assemblies sind Plugins in meinem Plugin-Framework. Sie haben überhaupt keinen Einstiegspunkt. Alles was ich weiß ist, dass sie einige Typen enthalten, die eine bestimmte Schnittstelle implementieren. Der alte, nicht-AppDomain-Code sieht wie folgt aus (leicht gekürzt):
try
{
string path = Path.GetFullPath("C:\library.dll");
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Assembly asm = Assembly.LoadFrom(path);
Type[] types = asm.GetExportedTypes();
foreach (Type t in types)
{
if ((t.GetInterface("IStarter") != null) && !t.IsAbstract)
{
object tempObj = Activator.CreateInstance(t);
MethodInfo info = t.GetMethod("GetParameters");
if (info != null)
{
return info.Invoke(tempObj, null) as string;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
if (args.Name.StartsWith("MyProject.View,"))
{
string path = Path.GetFullPath("C:\view.dll"));
return Assembly.LoadFrom(path);
}
return null;
}
Jetzt möchte ich, dass sie in einer eigenen AppDomain geladen werden:
try
{
string path = Path.GetFullPath("C:\library.dll");
AppDomain domain = AppDomain.CreateDomain("TempDomain");
domain.AssemblyResolve += CurrentDomain_AssemblyResolve; // 1. Exception here!!
domain.ExecuteAssembly(path); // 2. Exception here!!
domain.CreateInstanceFrom(...); // 3. I have NO clue, how the type is named.
domain.Load(...); // 4. I have NO clue, how the assembly is named.
domain.DoCallBack(...); // 5. Exception here!!
// ...
}
catch (Exception ex)
{
MessageBox.Show(String.Format("Damn '{0}'.", ex.Message), "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
Wie Sie sehen können, habe ich 5 Fälle eingegeben.
-
Wenn ich den Ereignishandler setze, erhalte ich eine Ausnahme, dass die Assembly (es ist eine Management Console (mmc.exe) SnapIn. nicht gefunden/geladen werden konnte.
-
ExecuteAssembly findet keinen Einstiegspunkt (nun, es gibt keinen).
-
Ich habe keine Ahnung, wie der Typ benannt ist. Wie kann man nach Schnittstelle laden?
-
Ähnlich wie bei 3. wie erhält man den Namen einer Baugruppe?
-
Gleicher Fehler wie unter 1.
Ich denke, das Problem könnte irgendwie an der Verwaltungskonsole liegen oder ich habe einfach keine Ahnung, was ich falsch mache. Für jede Hilfe bin ich dankbar.
UPDATE 1
Ich habe nun versucht, die gepostete Proxy-Lösung zu verwenden.
AppDomain domain = AppDomain.CreateDomain("TempDomain");
InstanceProxy proxy = domain.CreateInstanceAndUnwrap(Assembly.GetAssembly(
typeof(InstanceProxy)).FullName, typeof(InstanceProxy).ToString()) as InstanceProxy;
if (proxy != null)
{
proxy.LoadAssembly(path);
}
AppDomain.Unload(domain);
public class InstanceProxy : MarshalByRefObject
{
public void LoadAssembly(string path)
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
Assembly asm = Assembly.LoadFrom(path);
Type[] types = asm.GetExportedTypes();
// ...see above...
}
}
Auch das funktioniert nicht. Wenn ich versuche, das Proxy-Objekt zu erstellen, erhalte ich eine Ausnahme:
Die Datei oder Assembly 'MyProject.SnapIn, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' oder eine ihrer Abhängigkeiten konnte nicht geladen werden. Das System kann die angegebene Datei nicht finden.
Die Datei in der Fehlermeldung ist diejenige, die in mmc geladen wurde (das SnapIn). Gibt es eine Idee, wie man diesen Fehler beheben kann? AppDomain.AssemblyResolve wird nicht aufgerufen (weder in der alten noch in der neuen Domäne).
UPDATE 2
Ich habe jetzt die Lösung mit dem AppDomainSetup ausprobiert. Jetzt hat sich die Ausnahme in:
Die Datei oder Assembly 'file:///C:/Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL' oder eine ihrer Abhängigkeiten konnte nicht geladen werden. Der angegebene Assembly-Name oder die Codebase war ungültig. (Ausnahme von HRESULT: 0x80131047)
Irgendeine Idee?