On m'a donné 2 dll pré-compilées:
Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL
Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL
Exemple de différences dans les API:
Et j'essaye de charger les deux dans un seul projet pour faire quelque chose comme ceci:
extern alias v10;
extern alias v20;
private static void UpgradeUser()
{
// Load old user
var userOld = new v10::Common.Data.UserData();
userOld.loadData("user.dat");
// Create new user
var userNew = new v20::Common.Data.UserData();
// Copy properties
userNew.FirstName = userOld._firstName;
userNew.LastName = userOld._lastName;
userNew.Age = userOld._age;
// Invoke method from v10 and v20 API
userOld.version();
userNew.DisplayVersion();
if (userNew.GetUserInfo() != userOld.getInfo())
{
throw new Exception("Discrepencies in upgrade ");
}
Console.WriteLine("Upgrade done!");
}
J'ai configuré mes références de projet et app.config
à ce qui suit. Je copie également manuellement les dll dans mon dossier de sortie, ce qui correspond aux hrefs appconfig.
<!-- [Edited: see history for previous version] -->
<Reference Include="Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
<HintPath>libs\Common.Data.1_0_0_0.dll</HintPath>
<Aliases>v10</Aliases>
</Reference>
<Reference Include="Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
<HintPath>libs\Common.Data.2_0_0_0.dll</HintPath>
<Aliases>v20</Aliases>
</Reference>
<runtime>
<assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Data" publicKeyToken="f3b12eb6de839f43" culture="neutral" />
<codeBase version="1.0.0.0" href="libs\Common.Data.1_0_0_0.dll" />
<codeBase version="2.0.0.0" href="libs\Common.Data.2_0_0_0.dll" />
</dependentAssembly>
</assemblyBinding>
</runtime>
J'ai réussi à construire avec succès.
Mais lorsque j'essaie de l'exécuter, j'obtiens une MissingMethodException
pour UserData.loadData
.
J'ai lu plusieurs articles sur stackoverflow, des articles msdn et codeproject, mais je n'arrive pas à le faire fonctionner.
Lien 1 , Lien 2 , Lien 3 , Lien 4
Pense que je manque une étape importante mais ne peux pas comprendre quoi et pourrait vraiment avoir besoin d’aide.
[Edit1]
J'ai essayé d'utiliser les dll séparément, et elles fonctionnent. (Suppression de l'encombrement. Voir l'historique des versions pour les captures d'écran)
[Edit2]
J'ai essayé la proposition de Mukesh Kumar et modifié mon app.config en:
<runtime>
<assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Common.Data"
publicKeyToken="f3b12eb6de839f43"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
Mais cela ne fonctionne toujours pas. Je reçois maintenant FileNotFoundException
.
[Edit3]
Ok, je suis presque sûr que le <bindingRedirect>
n’est pas correct et devrait plutôt être <codeBase>
.
J'ai essayé de compiler à partir de la CLI:
csc Program.cs /reference:v10=libs/Common.Data.1_0_0_0.dll /reference:v20=libs/Common.Data.2_0_0_0.dll
Et ça marche bien. J'ai pu utiliser les deux API en même temps:
Mais lorsque j'essaie de le construire à partir de Visual Studio, il se plaint de/référence, même si j'ai déjà spécifié l'alias de référence:
The extern alias 'v10' was not specified in a /reference option
J'ai essayé de modifier <Reference />
pour inclure/exclure <SpecificVersion>True</SpecificVersion>
sans aucun effet.
J'ai trouvé ce post , où la solution consistait à supprimer et à rajouter les chemins. À l'aide de cette solution, Visual Studio fonctionne correctement, mais je suis revenu à System.MissingMethodException
.
On se croirait presque l'avoir, mais pas tout à fait. Comment puis-je obtenir Visual Studio pour générer correctement?
[Edit4]
J'ai essayé la méthode de Miguel, mais je ne travaille toujours pas.
Dans cette tentative, j'ai renommé les DLL en leur nom d'origine et je les ai stockées dans des dossiers différents.
J'ai ensuite mis à jour app.config pour faire un bindingRedirect ainsi que du code base.
En l'exécutant, je reçois MissingMethodException
.
Je ne savais pas trop ce que voulait dire 4- Find the and put in False
. J'ai donc essayé toutes les combinaisons de <Private>
, <SpecificVersion>
, ainsi que le paramétrage de <Reference Include>
sur FQN, mais aucune de ces combinaisons ne fonctionne.
En regardant ma 3ème édition, j'ai réussi à compiler et à exécuter l'exemple avec succès (avec mes hll renommés dlls + app.config codebase) lorsque vous avez terminé via l'interface de ligne de commande.
Mon problème est maintenant, comment puis-je configurer mon csproj, donc il construit la même chose.
Vous devez utiliser un assembly dépendant avec bindingRedirect, mais vous devez également placer des dll dans un dossier différent ou enregistrer sous un nom différent. Ceci fait, vous devez mettre ce qui suit dans votre app.config:
<assemblyBinding xmlns="urn:schemas-Microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="here token dll"
culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
<bindingRedirect oldVersion="1.0.0.1-2.0.0.0" newVersion="2.0.0.0" />
<codeBase version="1.0.0.0" href="folder\namedll.dll" />
<codeBase version="2.0.0.0" href="folder\namedll.dll" />
</dependentAssembly>
</assemblyBinding>
Avec ce code devrait compiler et exécuter, mais parfois, VS supprime ou remplace le code dans le fichier app.config lorsqu’il est compilé. Vous devez le vérifier dans le fichier de configuration du dossier de compilation. Si cela réussit, vous pouvez modifier le fichier .csproj. Pour cela vous devez faire:
1- Décharger le projet concerné
2- Faites un clic droit sur le projet
3- Cliquez sur Editer le projet
4- Recherchez la propriété<AutoGenerateBindingRedirects>
et définissez-la sur False
5- Enregistrer les modifications et recharger le projet
Cela fonctionne pour moi. Dans mon projet, j'utilise deux versions d'Automapper.
Enfin, une autre solution consiste à utiliser l'événement de construction AppDomain.CurrentDomain.AssemblyResolve
et à charger la DLL spécifique.
Pour cela, vous devez assister à l'événement:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
//debug and check the name
if (args.Name == "MyDllName")
return Assembly.LoadFrom("c:\\pathdll\midllv1.dll")
else if(args.Name ="MyDllName2")
return Assembly.LoadFrom("c:\\pathdll\midllv2.dll");
else
return Assembly.LoadFrom("");
}
En l'absence d'une réponse complète qui répond à mes besoins, j'ai décidé de faire don de ma solution avec la méthode AssemblyResolve
pour utiliser deux dll et charger le fichier correspondant à partir du fichier, en utilisant la réflexion pour résoudre le type. Pour cette démonstration, j'ai créé deux DLL appelées MathFuncs
. Si vous essayez d'appeler leur fonction Add.add
, le problème sera résolu en deux implémentations différentes. Pour voir les différents résultats, basculez l'entier de la version entre les valeurs 1 et 2:
public static int version = 1;
public static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += Program.CurrentDomain_AssemblyResolve;
version = 1;
Type a = Type.GetType("MathFuncs.Add, MathFuncs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
MethodInfo methodInfo = a?.GetMethod("add");
object result = null;
if (methodInfo != null)
{
object[] parametersArray = new object[] {1, 2};
result = methodInfo.Invoke(Activator.CreateInstance(a, null), parametersArray);
}
if (result != null)
{
Console.WriteLine((int)result);
}
else
{
Console.WriteLine("failed");
}
Console.Read();
}
public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
FileInfo fi = null;
if (version == 1)
{
fi = new FileInfo("C:\\Users\\ohbitton\\Desktop\\MathFuncs\\MathFuncs.dll");
}
else
{
fi = new FileInfo("C:\\Users\\ohbitton\\Desktop\\MathFuncs2\\MathFuncs.dll");
}
return Assembly.LoadFrom(fi.FullName);
}
Pour obtenir le nom complet de l'espace de noms pour le Type.GetType
, vous pouvez utiliser Powershell:
([system.reflection.Assembly]::loadfile("C:\Users\ohbitton\Desktop\MathFuncs\MathFuncs.dll")).FullName
Essayez de mettre vos détails de configuration comme suit.
<dependentAssembly>
<assemblyIdentity name="myAssembly"
publicKeyToken="32ab4ba45e0a69a1"
culture="neutral" />
<bindingRedirect oldVersion="1.0.0.0"
newVersion="2.0.0.0"/>
</dependentAssembly>
ici, vous pouvez vous fournir l'ancienne version de la DLL et la nouvelle version. Vous pouvez simplement suivre cet article article et aussi ceci .
J'espère que ceci vous aidera.