Chargement / déchargement de l'assemblage dans différents AppDomain

J'ai besoin d'exécuter une méthode dans un assembly chargé pendant l'exécution. Maintenant, je veux décharger ces assemblys chargés après l'appel de méthode. Je sais que j'ai besoin d'un nouveau AppDomain pour pouvoir décharger les bibliothèques. Mais ici, le problème se pose.

Les assemblys qui vont se charger sont des plugins dans mon framework de plugin. Ils n'ont pas de point d'entrée du tout. Tout ce que je sais est qu'ils contiennent des types qui implémentent une interface donnée. L'ancien code non-AppDomain 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 se 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, j'ai mis dans 5 cas.

  1. Si je définis le gestionnaire d'événements, je reçois une exception que l'assembly (c'est une console de gestion (mmc.exe) composant logiciel enfichable. impossible d'être trouvé / chargé.

  2. ExecuteAssembly ne trouve pas de point d'entrée (Eh bien, il n'y en a pas).

  3. Je n'ai aucune idée de comment le type est nommé. Comment charger par interface?

  4. Similaire à 3. Comment obtenir le nom d'un ensemble?

  5. Même erreur que dans 1.

Je pense que le problème pourrait être la console de gestion en quelque sorte ou je n'ai aucune idée de ce que je fais mal. Toute aide est appréciée.

Mise à jour 1

J'ai maintenant essayé d'utiliser la solution proxy 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 vous essayez de créer l'objet proxy, j'obtiens une exception:

Impossible charger le fichier ou l'assemblage '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 on chargé dans mmc (le SnapIn). Une idée de comment corriger cette erreur? Domaine d'application.AssemblyResolve n'est pas appelé (ni dans l'ancien ni dans le nouveau domaine).

Mise à jour 2

J'ai maintenant essayé la solution avec AppDomainSetup. Maintenant, l'exception a changé à:

Impossible de charger le fichier ou le fichier d'assemblage: / / / C: / Development / MyProject/bin/SnapIn / MyProject.Composant logiciel enfichable.DLL' ou une de ses dépendances. Le nom d'assembly ou la base de code donnés n'était pas valide. (Exception de HRESULT: 0x80131047)

Une idée?

22
demandé sur Scoregraphic 2010-01-25 16:45:13

3 réponses

Essayez ceci:

namespace SeperateAppDomainTest
{
    class Program
    {
        static void Main(string[] args)
        {
            LoadAssembly();
        }

        public static void LoadAssembly()
        {
            string pathToDll = Assembly.GetExecutingAssembly().CodeBase;
            AppDomainSetup domainSetup = new AppDomainSetup { PrivateBinPath = pathToDll };
            var newDomain = AppDomain.CreateDomain("FooBar", null, domainSetup);
            ProxyClass c = (ProxyClass)(newDomain.CreateInstanceFromAndUnwrap(pathToDll, typeof(ProxyClass).FullName));
            Console.WriteLine(c == null);

            Console.ReadKey(true);
        }
    }

    public class ProxyClass : MarshalByRefObject { }
13
répondu BFree 2010-01-25 14:35:15

Jetez un oeil à cette réponse précédente: Comment charger un assembly dans différents AppDomain sur Windows Mobile (. Net CF) ?. Cette réponse crée une classe proxy qui s'exécute dans un nouveau contexte AppDomain, vous pouvez donc avoir le contrôle total de votre initialisation.

Vous pouvez créer une méthode Start() dans la classe ServiceApplicationProxy et l'appeler normalement depuis votre hébergeur avec un proxy.Start().

1
répondu Rubens Farias 2017-05-23 12:25:45

Https://msdn.microsoft.com/en-us/library/3c4f1xde%28v=vs.110%29.aspx

Spécifie que

Nom de type Type: System.Chaîne

The fully qualified name of the requested type, including the namespace but not the assembly, as returned by the Type.FullName

Propriété.

Essayez donc d'appeler avec un nom complet, au lieu d'utiliser typeof(InstanceProxy).ToString() Utilisez string / text "<<Namespace>>.InstanceProxy"

Comme ci-dessous

InstanceProxy proxy = domain.CreateInstanceAndUnwrap(path, "<<Namespace>>.InstanceProxy") as InstanceProxy;
0
répondu Khavasi 2016-11-24 14:28:46