2016-02-16 2 views
1

Pour certains contextes: Je suis déjà en cours d'exécution dans un domaine "plugin" fourni par une application tierce. Ceci est important car cela limite ce qui peut être fait quand il s'agit de classer. Plus précisément, cette application repose sur certaines dll de base prédéfinies pour être sur le chemin de base de l'application classique, et charge tout le reste dynamiquement à partir d'une base de données. Bien que je n'ai pas de vue dans cette couche, il ne semble pas utiliser le système de fichiers (sorte de fichier temporaire) donc je suppose qu'il charge toutes les DLL qui ne sont pas directement dans la mémoire comme des tableaux d'octets.Chargé un assembly dans Appdomain depuis la mémoire, createinstance a pour résultat l'exception 'filenotfound'

J'ai une DLL chargée en tant que référence intégrée qui nécessite un certain app.config et un répertoire bin non contrôlable dans le contexte du plugin, donc je prévois d'utiliser un domaine d'application. La ressource DLL intégrée dans le plugin est lue en tant que tableau d'octets et injectée dans le domaine d'application. La DLL apparaît dans AppDomain.GetAssemblies() pour l'appdomain créé, cependant, lorsque je tente de créer une instance à partir de cette DLL, elle se plaint d'un "FileNotFound". J'ai vérifié que les FullNames correspondent, etc. Cela soulève la première et la plus simple question: pourquoi est-il à la recherche d'une DLL déjà chargée? Il semble qu'il omette intentionnellement tous les assemblys chargés par byte-array dans le but de rechercher des types. J'ai essayé de désactiver le sondage de base de chemin et cela change juste l'erreur d'un FileNotFound à une erreur plus générique de référence non trouvée. Voici le code qui essaie d'utiliser une DLL injectée en mémoire et échoue.

public AdsAdapter(Context context) 
     { 

      try 
      { 
       var adsPath = session.GetSystemSetting("SpecialConfig"); 
       var adsBin = Path.Combine(session.GetSystemSetting("SpecialBin"), @"special\path"); 

       AppDomainSetup appSetup = new AppDomainSetup() 
       { 
        ApplicationName = "ExtendsProxyOC", 
        ApplicationBase = adsBin, 
        PrivateBinPath = AppDomain.CurrentDomain.BaseDirectory, 
        ConfigurationFile = System.IO.Path.Combine(adsPath,"cs_client_app.config") 
       }; 

       _adsDomain = AppDomain.CreateDomain("adsDomain"+Guid.NewGuid(), 
        null,appSetup); 

       // add inmemory DLL 

       var dll = Assembly.GetAssembly(typeof(AdsAdapter)) 
         .GetManifestResourceStream(resourcespath + "ADSOCWrapper.dll"); 
       var dlldbg = Assembly.GetAssembly(typeof(AdsAdapter)) 
        .GetManifestResourceStream(resourcespath + "ADSOCWrapper.pdb"); 
       Assembly asmWrapper = _adsDomain.Load(StreamToBytes(dll), StreamToBytes(dlldbg)); 

       // Load a file which IS in the bin directory filesystem 
       _adsDomain.Load("ads_core"); 

       // the DLL IS in memory at this point and this proves it. Type definitions are there, looks fine. 
       Assembly[] assm = _adsDomain.GetAssemblies(); 

       // error occurs here "FileNotFound" in the app base for the .DLL file. Why is it trying to load from disk when it is already loaded? 
       _proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper", 
        typeof(AdsRemote).FullName, 
        true, //case search 
        System.Reflection.BindingFlags.CreateInstance, //bindingattr 
        null, //Binder 
        new object[]{}, //args 
        null, //culture 
        null);//activationattr 


      } 
      catch (Exception e) 
      { 
       throw e; 
      } 
     } 

     static byte[] StreamToBytes(Stream input) 
     { 
      var capacity = input.CanSeek ? (int)input.Length : 0; 
      using (var output = new MemoryStream(capacity)) 
      { 
       int readLength; 
       var buffer = new byte[4096]; 

       do 
       { 
        readLength = input.Read(buffer, 0, buffer.Length); 
        output.Write(buffer, 0, readLength); 
       } 
       while (readLength != 0); 

       return output.ToArray(); 
      } 
     } 

} 

Mon prochain mouvement était d'essayer primordial du processus de résolution de l'Assemblée, que je pense qu'elle pourrait être la réponse, mais comme je n'ai pas un « ancre » dll du système de fichiers, il semble que je ne suis pas capable d'amorcer mon code personnalisé.

Même si vous utilisez des fonctions de délégué anonymes dans mon AppDomainSetup.AppDomainInitializer, il est apparemment dépendant d'autres DLL disponibles. J'appelle seulement les objets GAC dans mon délégué, mais cela nécessite que l'assembly exécutant parent (celui qui configure le domaine d'application) soit chargé dans le domaine d'application cible. Afin de passer un délégué anonyme. Pourquoi?

Impossible de charger le fichier ou l'assemblage 'ParentAssembly, 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é.

AppDomainInitializer = new AppDomainInitializer(delegate(string[] target) 
          { 
           AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs args) 
           { 
            if (args.Name.Contains("ADSOCWrapper")) 
            { 
             return Array.Find(AppDomain.CurrentDomain.GetAssemblies(), 
              x => x.FullName.Contains("ADSOCWrapper")); 
            } 
            return null; 
           }; 
          }) 

En conséquence, je suis coincé incapable de faire mon look appdomain en mémoire pour ses types, il semble. Des idées ici?

+0

En utilisant Assembly.Load (octet []) est en général une idée assez mauvaise, très gaspillage. Et échouera carrément sur un assembly en mode mixte, comme le genre qui est un "wrapper" pour ce qui ressemble à du bricolage de code natif avec le répertoire actif. –

Répondre

1

La surcharge que vous utilisez de CreateInstanceFromAndUnwrap prend le fichier d'assembly au lieu du nom d'assembly.

surcharge Essayez de CreateInstanceFromAndUnwrap qui prend assembly name comme argument:

 _proxy = (AdsRemote)_adsDomain.CreateInstanceFromAndUnwrap("ADSOCWrapper", 
       typeof(FeedDao).FullName); 
+0

Cette méthode est obsolète dans ma version de .NET et génère une erreur d'exécution à propos de la nécessité d'une stratégie CAS. Je ne pense pas que nos architectes de système le permettront après avoir fait plus de recherche –

+0

Quelle version du framework vous travaillez? J'ai ce code en production. Peut-être vous devriez utiliser la version la plus simple 'appdomain.CreateInstanceFromAndUnwrap (" ADSOCWrapper ", typeof (FeedDao).FullName); ' – vendettamit

+0

Parce que la surcharge que vous utilisez attend' assemblyfile' c'est certain. – vendettamit