58 votes

Pourquoi mon paquet .NET Standard NuGet déclenche-t-il tant de dépendances?

J'ai été coucher avec un .NET de projet Standard et NuGet. J'ai un projet de travail, et ont transféré à NuGet.org. Mon projet objectifs .NET la Norme 1.3, ce qui devrait soutenir .NET Framework 4.6 et .NET Core 1.0.

Mais quand j'ai essayé d'ajouter mon projet (via NuGet) pour un nouveau .NET Framework 4.6 projet, les dépendances résolues à 47 paquets! Ils sont tous les systèmes de bibliothèques et semblent être les dépendances de Microsoft.NETCore.Les plates-formes ou NETStandard.Bibliothèque 1.6.1. (Gist de plein PM de sortie.)

Mon projet seulement les importations (using) une poignée de bibliothèques, aucune de laquelle j'ai ajouté manuellement; c'est à dire qu'ils sont de toutes les bibliothèques qui "est venu avec" .NET Standard. Ces bibliothèques sont:

  1. Système
  2. Système.Texte
  3. Système.La réflexion
  4. Système.Linq
  5. Système.Les Collections.Générique;

La chose est, j'ai décidé de faire mon projet cible .NET Standard parce que je voulais qu'il fonctionne de façon transparente à travers .NET Framework et .NET applications de Base. Je pensais que le point de l'ensemble de la Norme est de fixer un niveau minimum de compatibilité. Par extension, je suppose que j'avais suppose (peut-être à tort) que les bibliothèques comme Système.La Console serait automatiquement disponibles dans le Noyau ou le Cadre.

Je n'ai rien remarqué de ce genre quand j'ai testé mon projet de Norme comme une dépendance dans un Cadre et un projet de Base au sein de la même solution, donc je me méfie que cela pourrait être une NuGet chose.

Ce qui se passe réellement ici? Et comment puis-je faire de mes .NET de la bibliothèque Standard disponibles sur NuGet sans une énorme liste de dépendances?

Est-ce un problème avec la façon dont j'ai précisé que mon package NuGet? Ou ai-je fondamentalement mal compris quelque chose?

64voto

Martin Ullrich Points 5894

Vous n'avez rien fait de mal, ce qui est susceptible de se produire. Si vous voulez rien de plus que votre propre DLL être ajoutés à un nouveau .NET Framework de projet, vous avez pour cible .NET Standard 2.0 pour votre bibliothèque d'attente pour une .NET Framework version qui prend en charge à la fois de l'API et de l'assemblée versions - qui va être 4.7.2 (tout en .NET Framework 4.7.1 prend en charge toutes les Api, il y avait des bugs avec la façon dont certains assemblages sont versionnés et donc de l'outillage (VS 2017 15.5+) va ajouter des assemblées de le corriger).

Ce que vous voyez sont les effets secondaires du comment .NET Standard est construit et le soutien pour les prises en charge des cadres est mis en œuvre. C'est également différente .NET version Standard vous permet de cibler et de l'outillage utilisé pour faire référence à la bibliothèque de package.

Dans .NET Standard < 2.0, vous faites référence à l' NETStandard.Library meta-paquet qui à son tour références supplémentaires (System.*) des paquets. Ces paquets contiennent la référence à des assemblées qui composent le ".NET Contrat Standard" - un ensemble d'Api et de l'assemblée des noms + les versions.

Lorsque le package NuGet vous créer pour .NET Standard 1.0-1.6 est référencée par une application, chacun de ces paquets n'apporte pas la référence assemblées, mais plutôt de la mise en œuvre des assemblages pour le cadre de l'application des objectifs.

Pour .NET de Base, ces dernières correspondent aux assemblages qui font déjà partie de l'exécution afin que les fichiers DLL ne finira pas à côté de l'application. Ce qui a changé cependant, quand une nouvelle série de paquets a été publié pour .NET de Base 1.1 (NETStandard.Library version 1.6.1). Il en est résulté dans les applications conçues pour .NET Core 1.0 finir obtenir plus récente de la mise en œuvre des assemblages qui sont censés être inclus dans .NET de Base 1.1 (heureusement, 1.1 a ensuite fait le "support à long terme" version depuis qui a déclenché une discussion sur les assemblys qui font partie de la LTS promesse).

Sur .NET Framework de ces bibliothèques (avec quelques exceptions comme System.Net.Http) ne font pas beaucoup - ils juste à l'avant du système des assemblées. Ainsi, par exemple, le "contrat" qui définit System.Object est définie dans un System.Runtime.dll de l'assemblée. Si l' System.Runtime.dll le fichier, vous vous retrouvez avec dans une .NET Framework application contient un System.Runtime.dll qui contient le type à l'avenir .NET Framework mscorlib.dll. .NET de Base contient déjà un autre System.Runtime.dll qui fait quelque chose de différent pour cette plate-forme. Ce mécanisme permet à un fichier DLL à travailler sur les deux plates-formes, puisque celles-type de vers l'avant et supplémentaires implémentations d'assurer un "contrat" (types + assemblages + assemblée versions) à travailler sur les deux implémentations.

.NET Standard 2.0 visant à réduire le nombre de colis et les Dll nécessaires et aussi de supprimer nécessitant des mises à jour de NETStandard.Library chaque fois qu'un nouveau .NET de Base version est disponible.

Donc, pour .NET Standard 2.0 et .NET Core 2.0, l' NETStandard.Library package apporte seulement des assemblies de référence pour la compilation d'un code à un projet, mais le résultat de package NuGet ne dépend plus de ce package. Ainsi, lorsque vous créez une bibliothèque de ciblage .NET Standard 2.0 et de le publier, il n'aura pas de NuGet dépendances (sauf si vous en ajouter d'autres).

Dans la logique de ce "bibliothèques de prise en charge" à apporter lors de la consommation d'un .NET de la bibliothèque Standard a été déplacé à l'outillage qui est utilisé lors de la construction. Alors, quand une bibliothèque qui contient une référence à un netstandard.dll est ajouté à une .NET Framework projet, la capacité de l'outil puis ajouter le soutien nécessaire de la Dll de la version de .NET Framework utilisé. Cela a été fait pour .NET Standard 2.0 ainsi que .NET Standard 1.5+ depuis .NET Framework 4.6.1 a été rétroactivement fait compatible avec .NET Standard 2.0 (1.4 a été précédemment) par le biais de ces types de fichiers DLL. Le même outillage assure également que même si les packages NuGet sont en quelque sorte amené à un tel projet d'application, tout .NET Standard de mise en œuvre de bibliothèques apporté via NuGet sont retirés de la construction. Donc, si vous faites référence à un .NET Standard 1.0 package NuGet qui a été construit lors de l' .NET Core 1.0 a été publié, tous ses NuGet dépendances sont garnis et vous obtenez les bibliothèques de support livré avec la construction de l'outillage à la place.

L'idée était que .NET Framework 4.7.1 contiendrait toutes les assemblées "boîte de réception", pour qu' netstandard.dll, System.Runtime.dll etc. font partie de .NET Framework et tout .NET Standard 1.0-2.0 fichier DLL serait "juste travail", le problème est que ces "boîte de réception" fichiers dll a une trop faible, le numéro de version pour certaines assemblées ainsi, les bibliothèques ne charge ce problème a été résolu par la modification de l'outillage à nouveau pour inclure les fichiers DLL avec plus de numéros de version dans le soutien des bibliothèques qui, à son tour avant de la "boîte de réception" .NET Framework assemblées. Ceci est prévu pour être fixé .NET Framework 4.7.2.

5voto

Kevinoid Points 745

Je viens de tomber sur ce problème. Le blog est lié à un commentaire de Martin Ullrich réponse m'a conduit à une solution qui a fonctionné pour moi: à l'Aide de NuGet multi-ciblage. En modifiant:

<TargetFramework>netstandard1.0</TargetFramework>

pour

<TargetFrameworks>netstandard1.0;netstandard2.0;net45</TargetFrameworks>

dans le projet .csproj le fichier. Cela entraîne que le projet soit construit séparément pour chaque cible cadre et le package NuGet ne dépend NETStandard.Library pour netstandard1.0. Depuis NuGet choisit l' net45 binaires pour tout plein .NET Framework version, cela permet d'éviter l'inutile dépendances lors de l'installation du package.

0voto

CAD bloke Points 2986

Si vous êtes sur .NET de 4,6 et vous êtes à essayer de comprendre quels sont ceux qui vous avez besoin pour déployer, la recherche de votre fichier CSPROJ pour \System. (pas une regex) - ils sont ceux dans des paquets qui doivent être copiés avec votre application, le reste doit être du cadre de Dll.

Pour tester cette théorie se débarrasser d'eux dans vos locaux à construire et à exécuter qu'à assurez-vous que la version déployée ne cassera pas...

  • Dans le dossier bin, n' dir /b System*.dll > textfile.txt pour obtenir une liste des Dll.
  • inséré "DEL" en face de tous les noms,
  • J'ai aussi trouvé Microsoft.Win32.Primitives.dll & netstandard.dll qui n'étaient pas nécessaires dans 4.6 soit.
  • et l'enregistrer en tant que .Fichier CMD - euh, non pas dans le dossier bin ok?
  • ajouter un post-processus de construction. $(ProjectDir)DeleteSuperfluousSystemDlls.cmd

J'aimerais descendre .NET de 4,6 mais AutoCAD sauts de mal lorsque le cadre est trop moderne pour lui.

edit...

Voici quelques copier-coller ...

Étape 1 - dans votre fichier CSPROJ ...

<!--https://stackoverflow.com/questions/2387456/msbuild-exec-task-without-blocking/21181071#21181071-->
  <!--Launch a Process in Parallel-->
  <UsingTask TaskName="ExecAsync" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <!--The file path is the full path to the executable file to run-->
      <FilePath ParameterType="System.String" Required="true" />
      <!--The arguments should contain all the command line arguments that need to be sent to the application-->
      <Arguments ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs"><![CDATA[
  System.Diagnostics.ProcessStartInfo processStartInfo = new System.Diagnostics.ProcessStartInfo(FilePath, Arguments);
  processStartInfo.UseShellExecute = true;
  System.Diagnostics.Process.Start(processStartInfo);
  ]]></Code>
    </Task>
  </UsingTask>
  <Target Name="AfterBuild">
    <ExecAsync FilePath="$(ProjectDir)\Deployment\DeleteSuperfluousSystemDlls.cmd" Arguments="$(TargetDir)" />
  </Target>

Étape 2. Le fichier de commandes ...

Modifier la liste créée par l' dir /b System*.dll > textfile.txt de regarder un peu comme

del %1Microsoft.Win32.Primitives.dll
del %1netstandard.dll
del %1System.AppContext.dll
del %1System.Collections.Concurrent.dll
del %1System.Collections.dll
del %1System.Collections.NonGeneric.dll
del %1System.Collections.Specialized.dll
del %1System.ComponentModel.dll

mais n'oubliez pas de supprimer ceux qui ont réellement besoin de sorte qu'ils ne sont pas supprimées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X