2017-10-08 19 views
1

Mon objectif est d'exécuter certains "morceau de code", qui utilise certains assemblages, sur plusieurs versions de cet assemblage. La façon dont je fais cela est en exécutant ce "morceau de code" sur AppDomains séparés, un pour chaque version d'assemblage.Charger plusieurs versions d'assemblage dans plusieurs AppDomains

j'ai pu le faire que lorsque le « morceau de code » utilise l'ensemble à travers une réflexion, mais ce que je voudrais est d'avoir que « morceau de code » écrit de manière fortement typé.

En d'autres termes, disons que je l'assemblée suivante:

namespace ClassLibrary1 
{ 
    public class Class1 
    { 
     internal const string Version = "1.0.0.0"; 
     public string Method1() { return Version; } 
    } 
} 

En outre, il a la définition suivante dans AssemblyInfo.cs:

[assembly: AssemblyVersion(ClassLibrary1.Class1.Version)] 

Maintenant que j'ai un « Versions » dossier dans lequel j'ai plusieurs versions de cet assembly, par exemple:

/Versions/ 
├─ /1000/ 
│ └─ ClassLibrary1.dll 
├─ /1001/ 
│ └─ ClassLibrary1.dll 
└─ /1002/ 
    └─ ClassLibrary1.dll 

Maintenant à exécuter le « morceau de code » J'utilise l'application console suivante:

class Program 
{ 
    static void PieceOfCode(Assembly assembly) 
    { 
     Type class1Type = assembly.GetType("ClassLibrary1.Class1"); 
     dynamic class1 = Activator.CreateInstance(class1Type); 
     string vesion = class1.Method1(); 

     Console.WriteLine(vesion); 
    } 

    public sealed class SeparateDomainExecutor : MarshalByRefObject 
    { 
     public void Execute(Action<Assembly> action, string assemblyPath) 
     { 
      action(Assembly.LoadFrom(assemblyPath)); 
     } 
    } 

    static void Main(string[] args) 
    { 
     foreach (string file in Directory.EnumerateFiles(@"C:\Versions", "*.dll", SearchOption.AllDirectories)) 
     { 
      AppDomain domain = AppDomain.CreateDomain("ClassLibrary1 Domain"); 

      var type = typeof(SeparateDomainExecutor); 
      var runner = (SeparateDomainExecutor)domain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); 
      runner.Execute(PieceOfCode, file); 

      AppDomain.Unload(domain); 
     } 

     Console.Read(); 
    } 
} 

L'application de la console fonctionne très bien, mais je voudrais remplacer que l'utilisation de la réflexion dans « PieceOfCode » avec quelque chose comme ce qui suit:

static void PieceOfCode() 
{ 
    ClassLibrary1.Class1 class1 = new ClassLibrary1.Class1(); 
    Console.WriteLine(class1.Method1()); 
} 

Est-ce possible? Le problème que j'ai avec ceci est que le PieceOfCode serait écrit en utilisant une version spécifique de ClassLibrary1 (probablement le dernier) et je ne vois pas comment je pourrais "surcharger" cette version dans AppDomain séparé. J'ai essayé peu de choses, mais je finis toujours avec FileLoadException.

+0

si c'était un assembly nommé fort et vous connaissez la version avant de bien charger votre application, vous pouvez utiliser la redirection de liaison et changer la version dans app/web .config fichier –

+0

"fortement typé" est le contraire de "plusieurs versions" . .NET implémente une vérification de type forte en incluant le numéro de version de l'assembly dans l'identité de type. Une DLL forte Hell contre-mesure, mais clairement vous voulez créer l'enfer par le design. Donc vous ne voulez pas faire ça du tout. –

+0

Oui, exactement. Fondamentalement, je voulais ignorer la protection dll-enfer, le nom fort. – bellpatricia

Répondre

1

Malheureusement, lorsque vous écrivez ClassLibrary1.Class1 dans une partie de code statiquement typée, vous avez besoin d'une référence d'assembly et le compilateur utilise cette référence pour nommer une version donnée de la classe. Bien que les noms qualifiés (typeof(Class1).AssemblyQualifiedName) ne contiennent pas le chemin ou le nom de fichier de l'assemblée, que le nom de l'assemblage et la version, le chargeur de classe a d'autres limites que vous remarquerez peut-être:

  • il ne peut pas charger 2 classes différentes assemblées avec le même nom dans le même espace de noms
  • depuis chemin ou nom de fichier ne fait pas partie des références de montage, vous ne pouvez pas référencer 2 ensembles de compilation avec le même nom fort

la façon dont vous utilisez Assembly.LoadFrom(...) et liaison dynamique est le meilleur que je pourrais trouver. Et c'est ainsi que différentes versions d'assemblys Office sont généralement traitées à partir d'applications qui les intègrent.

La seule solution possible que je vois est de séparer morceau de code dans un ensemble séparé (par exemple, MyStaticIntegration.dll) compiler contre chaque version de votre dépendance (ClassLibrary1.dll) séparément, puis intégrer chaque version de MyStaticIntegration .dll dans votre application de la même manière que vous l'avez fait avec ClassLibrary1.dll avant.

Le même wall-of-dynamic restera dans votre application, mais vous pouvez affiner l'interface que vous utilisez dynamiquement avec cette astuce.

+0

Merci pour la réponse, malheureusement vous avez confirmé mon inquiétude. Néanmoins, merci pour la solution suggérée. – bellpatricia