Partager via


Comment NuGet résout les dépendances de package

Chaque fois qu’un package est installé ou réinstallé, ce qui inclut l’installation dans le cadre d’un processus de restauration , NuGet installe également tous les packages supplémentaires dont dépend ce premier package.

Ces dépendances immédiates peuvent également avoir des dépendances propres, ce qui peut continuer à une profondeur arbitraire. Cela produit ce qu’on appelle un graphique de dépendances qui décrit les relations entre les packages à tous les niveaux.

Lorsque plusieurs packages ont la même dépendance, le même ID de package peut apparaître plusieurs fois dans le graphique, potentiellement avec différentes contraintes de version. Toutefois, une seule version d’un package donné peut être utilisée dans un projet. NuGet doit donc choisir la version utilisée. Le processus exact dépend du format de gestion des packages utilisé.

Résolution de dépendances avec PackageReference

Lors de l’installation de packages dans des projets à l’aide du format PackageReference, NuGet ajoute des références à un graphique de package plat dans le fichier approprié et résout les conflits à l’avance. Ce processus est appelé restauration transitive. La réinstallation ou la restauration de packages est ensuite un processus de téléchargement des packages répertoriés dans le graphique, ce qui entraîne des builds plus rapides et plus prévisibles.

Vous pouvez également tirer parti des versions flottantes, telles que 2.8.*, pour éviter de modifier le projet afin d’utiliser la dernière version d’un package. Lorsque vous utilisez des versions flottantes, nous vous recommandons d’activer la fonctionnalité de verrouillage de fichier pour garantir la répétabilité.

Lorsque le processus de restauration NuGet s’exécute avant une build, il résout d’abord les dépendances en mémoire, puis écrit le graphique résultant dans un fichier appelé project.assets.json.

Le fichier de ressources se trouve à MSBuildProjectExtensionsPath, qui correspond par défaut au dossier « obj » du projet. MSBuild lit ensuite ce fichier et le traduit en un ensemble de dossiers où des références potentielles sont trouvées, puis les ajoute à l’arborescence du projet en mémoire.

Le fichier project.assets.json est temporaire et ne doit pas être ajouté au contrôle de code source. Elle est répertoriée par défaut dans .gitignore et .tfignore. Consultez Packages et la gestion de code source.

Règles de résolution des dépendances

La restauration transitive applique quatre règles principales pour résoudre les dépendances : version la plus basse applicable, versions flottantes, la dépendance directe prévaut, et dépendances "cousines".

Version la plus basse applicable

La règle de version la plus basse applicable restaure la version la plus faible possible d’un package telle que définie par ses dépendances. Elle s’applique également aux dépendances de l’application ou de la bibliothèque de classes, sauf si elle est déclarée comme flottante.

Dans la figure suivante, par exemple, la version 1.0-beta est considérée comme inférieure à 1.0. NuGet choisit donc la version 1.0 :

Choisir la version la plus basse applicable

Dans la figure suivante, la version 2.1 n’est pas disponible sur le flux, mais parce que la contrainte de version est >= 2.1 NuGet choisit la version la plus basse suivante qu’elle peut trouver, dans ce cas 2.2 :

Choisir la prochaine version la plus basse disponible sur le flux

Lorsqu’une application spécifie un numéro de version exact, tel que la version 1.2, qui n’est pas disponible sur le flux, NuGet échoue avec une erreur lors de la tentative d’installation ou de restauration du package :

NuGet génère une erreur lorsqu’une version exacte du package n’est pas disponible

Versions flottantes

Une version de dépendance flottante est spécifiée avec le caractère *. Par exemple, 6.0.*. Cette spécification de version indique « utiliser la dernière version 6.0.x » ; 4.* signifie « utiliser la dernière version 4.x ». L’utilisation d’une version flottante réduit les modifications apportées au fichier projet, tout en gardant à jour la dernière version d’une dépendance. Les versions flottantes ne peuvent être spécifiées qu’au niveau du projet.

Lorsque vous utilisez une version flottante, NuGet résout la version la plus élevée d’un package qui correspond au modèle de version, par exemple 6.0.* obtient la version la plus élevée d’un package qui commence par la version 6.0 :

Choisir la version 6.0.1 lorsqu’une version flottante 6.0.* est demandée

Version Versions présentes sur le serveur Résolution Raison Notes
* 1.1.0
1.1.1
1.2.0
1.3.0-alpha
1.2.0 Version stable la plus élevée.
1.1.* 1.1.0
1.1.1
1.1.2-alpha
1.2.0-alpha
1.1.1 Version stable la plus élevée qui respecte le modèle spécifié.
*-* 1.1.0
1.1.1
1.1.2-alpha
1.3.0-beta
1.3.0-beta Version la plus élevée, y compris les versions non stables. Disponible dans Visual Studio version 16.6, NuGet version 5.6, SDK .NET Core version 3.1.300
1.1.*-* 1.1.0
1.1.1
1.1.2-alpha
1.1.2-beta
1.3.0-beta
1.1.2-beta Version la plus élevée respectant le modèle et incluant les versions non stables. Disponible dans Visual Studio version 16.6, NuGet version 5.6, SDK .NET Core version 3.1.300
1.2.0-rc.* 1.1.0
1.2.0-rc.1
1.2.0-rc.2
1.2.0
1.2.0 Bien qu'il s'agisse d'une plage de versions avec une partie de préversion, les versions stables sont autorisées si elles correspondent à la partie stable. Étant donné que la version 1.2.0 > 1.2.0-rc.2 est mentionnée, elle est donc choisie.

Note

La résolution de version flottante ne prend pas en compte si un package est répertorié ou non. La résolution de versions flottantes est effectuée localement si les conditions peuvent être satisfaites avec les paquets dans le dossier de paquets global.

La dépendance directe l'emporte

Lorsque le graphique de package d’une application contient différentes versions d’un package dans le même sous-graphe et que l’une de ces versions est une dépendance directe dans ce sous-graphique, cette version sera choisie pour ce sous-graphe et le reste sera ignoré. Ce comportement permet à une application de remplacer n’importe quelle version de package particulière dans le graphique de dépendances.

Dans l’exemple ci-dessous, l’application dépend directement du package B avec une contrainte de version de >=2.0.0. L’application dépend également du package A, qui dépend également du package B, mais avec une contrainte >=1.0.0. Étant donné que la dépendance du package B 2.0.0 est une dépendance directe à l’application dans le graphique, cette version est utilisée :

Application utilisant la dépendance directe gagne la règle

Avertissement

La règle de priorité des dépendances directes peut entraîner un abaissement de la version du paquet, ce qui peut provoquer une rupture d'autres dépendances dans le graphe. Lorsqu’un package est rétrogradé, NuGet ajoute un avertissement pour alerter l’utilisateur.

Cette règle entraîne également une plus grande efficacité avec un graphique de dépendance volumineux. Lorsqu’une dépendance plus proche dans le même sous-graphe a une version supérieure à une autre, NuGet ignore cette dépendance, et NuGet ignore également toutes les dépendances restantes sur cette branche du graphique.

Dans le diagramme ci-dessous, par exemple, car le package C 2.0.0 est utilisé, NuGet ignore toutes les branches de ce sous-graphe qui font référence à une version antérieure du package C :

Lorsque NuGet ignore un package dans le graphique, il ignore cette branche entière

Grâce à cette règle, NuGet tente d’honorer l’intention de l’auteur du package. Dans le diagramme ci-dessous, l’auteur du package A a été explicitement rétrogradé au package C 1.0.0 à partir du package C 2.0.0.

Lorsqu’un auteur de package effectue explicitement une rétrogradation, NuGet respecte cela.

Le propriétaire de l’application peut choisir de mettre à niveau le package C vers une version supérieure à 2.0.0, ce qui n’entraîne pas de rétrogradation supplémentaire de la version pour le package C. Dans ce cas, aucun avertissement n’est déclenché.

Lorsqu’un honneur d’application ajoute une dépendance directe pour un package rétrogradé, NuGet respecte cela.

Dépendances cousines

Lorsque différentes versions de package sont référencées dans des sous-graphes différents dans le graphique de l’application, NuGet utilise la version la plus basse qui répond à toutes les exigences de version (comme avec les versions les plus basses applicables et versions flottantes règles). Dans l’image ci-dessous, par exemple, la version 2.0.0 du package B satisfait à l’autre contrainte >=1.0.0, et est donc utilisée :

Résolution des dépendances cousines à l’aide de la version inférieure qui satisfait à toutes les contraintes

Notez que les packages n'ont pas besoin d'être à la même distance pour que la règle des dépendances cousines s'applique. Dans le diagramme ci-dessous, le package D 2.0.0 est choisi dans le sous-graphe C du package et le package D 3.0.0 est choisi dans le sous-graphe du package A. Dans le sous-graphique d’application, il n’existe aucune dépendance directe avec le package D. Par conséquent, la la version la plus basse applicable règle est appliquée et la version 3.0.0 est choisie.

Résolution des dépendances cousines à l’aide de la version inférieure qui satisfait à toutes les contraintes à différentes distances

Dans certains cas, il n’est pas possible de répondre à toutes les exigences de version. Comme indiqué ci-dessous, si le package A nécessite exactement le package B 1.0.0 et que le package C nécessite le package B >=2.0.0, NuGet ne peut pas résoudre les dépendances et génère une erreur.

dépendances non résolues en raison d’une exigence de version exacte

Dans ces situations, le consommateur de niveau supérieur (l’application ou le paquet) doit ajouter sa propre dépendance directe au paquet B, afin que la règle sur la dépendance directe gagne s’applique.

Plages de versions et versions préliminaires avec PackageReference

Il n’est pas rare qu’un package ait des versions stables et préliminaires disponibles. Lors de la résolution d’un graphique de dépendances, NuGet décide s’il faut envisager des versions préliminaires d’un package en fonction d’une règle unique : If the project or any packages within the graph request a prerelease version of a package, then include both prerelease or stable versions, otherwise consider stable versions only.

Dans la pratique, sous la règle applicable la plus basse, cela signifie :

Plage de versions Versions disponibles Version sélectionnée
[1.0.0, 2.0.0) 1.2.0-beta.1, 1.2.0, 1.2.0
[1.0.0, 2.0.0-0) 1.2.0-beta.1, 1.2.0, 1.2.0-beta.1
[1.0.0, 2.0.0) 1.2.0-beta.1, 2.0.0-beta.3 Aucun, NU1103 est déclenché.
[1.0.0, 2.0.0-rc) 1.2.0-beta.1, 2.0.0-beta.3 1.2.0-beta.1

Résolution des dépendances avec packages.config

Avec packages.config, les dépendances d’un projet sont écrites dans packages.config sous la forme d’une liste plate. Toutes les dépendances de ces packages sont également écrites dans la même liste. Lorsque des packages sont installés, NuGet peut également modifier le fichier .csproj, app.config, web.configet d’autres fichiers individuels.

Avec packages.config, NuGet tente de résoudre les conflits de dépendances pendant l’installation de chaque package individuel. Autrement dit, si le package A est en cours d’installation et dépend du package B et que le package B est déjà répertorié dans packages.config comme dépendance d’un autre élément, NuGet compare les versions du package B demandées et tente de trouver une version qui satisfait à toutes les contraintes de version. Plus précisément, NuGet sélectionne la version inférieure major.minor qui satisfait aux dépendances.

Par défaut, NuGet 2.8 recherche la version corrective la plus basse (consultez notes de publication de NuGet 2.8). Vous pouvez contrôler ce paramètre via l’attribut DependencyVersion dans NuGet.Config et le commutateur -DependencyVersion sur la ligne de commande.

Le processus packages.config de résolution des dépendances est compliqué pour les graphiques de dépendance plus volumineux. Chaque nouvelle installation de package nécessite une traversée de l’ensemble du graphique et génère la possibilité de conflits de version. Lorsqu’un conflit se produit, l’installation est arrêtée, laissant le projet dans un état indéterminé, en particulier avec des modifications potentielles du fichier projet lui-même. Il ne s’agit pas d’un problème lors de l’utilisation d’autres formats de gestion de package.

Plages de versions et versions préliminaires avec packages.config

packages.config résolution n’autorise pas le mélange de dépendances stables et en préversion dans des graphes. Si une dépendance est exprimée avec une plage comme [1.0.0, 2.0.0), les packages de préversion ne sont pas autorisés dans le graphique.

Gestion des ressources de dépendance

Lorsque vous utilisez le format PackageReference, vous pouvez contrôler les ressources provenant des dépendances qui circulent dans le projet de niveau supérieur. Pour plus d’informations, consultez PackageReference.

Lorsque le projet de niveau supérieur est lui-même un package, vous avez également le contrôle sur ce flux à l’aide des attributs include et exclude avec des dépendances répertoriées dans le fichier .nuspec. Voir la référence .nuspec - Dépendances.

Exclusion des références

Il existe des scénarios dans lesquels les assemblys portant le même nom peuvent être référencés plusieurs fois dans un projet, produisant des erreurs au moment de la conception et au moment de la génération. Considérez un projet qui contient une version personnalisée de C.dll, et référence le package C qui contient également C.dll. En même temps, le projet dépend également du package B, qui dépend également du package C et du C.dll. Par conséquent, NuGet ne peut pas déterminer la C.dll à utiliser, mais vous ne pouvez pas simplement supprimer la dépendance du projet sur le package C, car le package B dépend également de celui-ci.

Pour résoudre ce problème, vous devez référencer directement le C.dll souhaité (ou utiliser un autre paquet qui fait référence au bon), puis ajouter une dépendance sur le paquet C qui exclut toutes ses ressources. Pour ce faire, procédez comme suit en fonction du format de gestion des packages en cours d’utilisation :

  • PackageReference : ajoutez ExcludeAssets="All" dans la dépendance :

    <PackageReference Include="PackageC" Version="1.0.0" ExcludeAssets="All" />
    
  • packages.config: supprimez la référence au packageC du fichier .csproj afin qu’elle référence uniquement la version de C.dll souhaitée.

Mises à jour des dépendances pendant l’installation du package

Si une version de dépendance est déjà satisfaite, la dépendance n’est pas mise à jour pendant d’autres installations de package. Par exemple, considérez le package A qui dépend du package B et spécifie la version 1.0 pour le numéro de version. Le référentiel source contient les versions 1.0, 1.1 et 1.2 du package B. Si A est installé dans un projet qui contient déjà B version 1.0, B 1.0 reste utilisé, car il satisfait à la contrainte de version. Toutefois, si le package A avait des demandes version 1.1 ou ultérieure de B, B 1.2 serait installé.

Résolution des erreurs de package incompatibles

Pendant une opération de restauration de package, vous pouvez voir l’erreur « Un ou plusieurs packages ne sont pas compatibles... » ou qu’un package « n’est pas compatible » avec l’infrastructure cible du projet.

Cette erreur se produit quand un ou plusieurs des packages référencés dans votre projet n’indiquent pas qu’ils prennent en charge l’infrastructure cible du projet ; autrement dit, le package ne contient pas de DLL appropriée dans son dossier lib pour une infrastructure cible compatible avec le projet. (Consultez les Frameworks Cibles pour obtenir une liste.)

Par exemple, si un projet cible netstandard1.6 et que vous tentez d’installer un package qui contient des DLL uniquement dans les dossiers lib\net20 et \lib\net45, vous voyez des messages comme suit pour le package et éventuellement ses dépendants :

Restoring packages for myproject.csproj...
Package ContosoUtilities 2.1.2.3 is not compatible with netstandard1.6 (.NETStandard,Version=v1.6). Package ContosoUtilities 2.1.2.3 supports:
  - net20 (.NETFramework,Version=v2.0)
  - net45 (.NETFramework,Version=v4.5)
Package ContosoCore 0.86.0 is not compatible with netstandard1.6 (.NETStandard,Version=v1.6). Package ContosoCore 0.86.0 supports:
  - 11 (11,Version=v0.0)
  - net20 (.NETFramework,Version=v2.0)
  - sl3 (Silverlight,Version=v3.0)
  - sl4 (Silverlight,Version=v4.0)
One or more packages are incompatible with .NETStandard,Version=v1.6.
Package restore failed. Rolling back package changes for 'MyProject'.

Pour résoudre les incompatibilités, effectuez l’une des opérations suivantes :

  • Reciblez votre projet vers une infrastructure prise en charge par les packages que vous souhaitez utiliser.
  • Contactez l'auteur des paquets et collaborez avec lui pour ajouter la prise en charge du framework que vous avez choisi. Chaque page de description de package sur nuget.org a un lien Contacter les propriétaires à cet effet.

Pourboire

solution alternative: NuGetSolver est une extension Visual Studio développée par Microsoft DevLabs, conçue pour faciliter la résolution des conflits de dépendances. Il automatise le processus d’identification et de résolution de ces problèmes. Pour plus d’informations, visitez la page NuGetSolver sur Visual Studio Marketplace et nous aimerions entendre vos commentaires sur votre expérience.