Je dois exécuter une méthode dans un ensemble chargé pendant l'exécution. Maintenant, je veux décharger les assemblys chargés après l'appel de la méthode. Je sais que j'ai besoin d'un nouvel AppDomain pour pouvoir décharger les bibliothèques. Mais ici, le problème se pose.Chargement/déchargement d'un ensemble dans un AppDomain différent
Les assemblages qui vont être chargés sont des plugins dans mon framework de plugin. Ils n'ont aucun point d'entrée du tout. Tout ce que je sais, c'est qu'ils contiennent des types qui implémentent une interface donnée. Le vieux, non-AppDomain code ressemble à ceci (légèrement raccourci):
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;
}
Maintenant, je veux qu'ils chargent dans un propre AppDomain:
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);
}
Comme vous pouvez le voir, je l'ai mis en 5 cas.
Si je mets le gestionnaire d'événements, je reçois une exception que l'ensemble (il est une console de gestion (mmc.exe) SnapIn. N'a pas été trouvé/chargé.
ExecuteAssembly ne trouve pas point d'entrée (bien, il n'y a pas).
Je n'ai pas la moindre idée comment le type est nommé. Comment charger par l'interface?
similaires à 3. Comment obtenir le nom d'un ensemble
?même erreur que dans 1.
Je pense que le problème pourrait être la console managment d'une façon ou j'ai juste aucune idée de ce que je fais mal. Toute aide est appréciée.
MISE À JOUR 1
J'ai maintenant essayé d'utiliser le proxy solution affichée.
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...
}
}
Cela ne fonctionne pas non plus. Lorsque j'essaie de créer l'objet proxy, j'obtiens une exception:
Impossible de charger le fichier ou l'assembly 'MyProject.SnapIn, Version = 1.0.0.0, Culture = neutre, PublicKeyToken = null' ou l'une de ses dépendances. Le système ne peut pas trouver le fichier spécifié.
Le fichier dans le message d'erreur est le sur chargé dans mmc (SnapIn). Une idée de comment corriger cette erreur? AppDomain.AssemblyResolve n'est pas appelé (ni dans l'ancien ou le nouveau domaine).
MISE À JOUR 2
J'ai maintenant essayé la solution avec le AppDomainSetup. Maintenant, l'exception a été remplacée par:
Impossible de charger le fichier ou l'assemblage 'file: /// C: /Development/MyProject/bin/SnapIn/MyProject.SnapIn.DLL' ou l'une de ses dépendances. Le nom d'assembly ou la base de code donné était invalide. (Exception de HRESULT: 0x80131047)
Une idée?
Avez-vous essayé de créer une classe qui hérite de MarshallByRef à agir en tant que proxy et laissez-le faire ce sale boulot dans un nouveau contexte de domaine d'application? –
Est-ce que cette classe serait dans l'assemblage à charger ou dans l'assemblage déjà chargé (celui qui essaie de charger les autres)? – Scoregraphic
s'il vous plaît, voir ma réponse ci-dessous –