Comment obtenir des projets .NET Core pour copier des références NuGet dans la sortie de génération?

112

J'essaye d'écrire un système de plugin avec .NET Core, et l'une de mes exigences est de pouvoir distribuer la DLL du plugin avec ses dépendances à l'utilisateur pour l'installation.

Cependant, je ne peux pas comprendre comment inclure mes dépendances NuGet en tant qu'artefact de construction et les faire sortir dans le dossier de construction, sans avoir à les utiliser dotnet publishcomme un hack. Existe-t-il un moyen de le spécifier dans le fichier .csproj (fichier projet)?

chyyran
la source
2
Pourquoi utiliser dotnet publishserait-il un hack? Incluez la commande dans votre fichier csproj en tant que script de post-génération.
Austin Drenski
3
dotnet publishjette tout le framework dans le dossier de publication, puisque j'écris un plugin, la majorité des fichiers ne sont pas nécessaires car le framework serait déjà chargé par le programme bootstrapper. Je recherche quelque chose de similaire au fonctionnement des builds sur .NET Framework.
chyyran
Et inclure <CopyToOutputDirectory>Always</CopyToOutputDirectory>dans votre csproj sur chacune des dll que vous souhaitez déplacer ne fait pas l'affaire? Peut-être combiné avec un <link>nœud?
Austin Drenski
7
<PackageReference/>ne prend pas en charge <CopyToOutputDirectory>.
chyyran
1
Le "framework entier" vient de NuGet cependant .. et si vous choisissez de copier tous les assemblys NuGet dans la sortie de construction, vous les obtiendrez tous ..
Martin Ullrich

Réponses:

180

Vous pouvez l'ajouter à l' <PropertyGroup>intérieur de votre fichier csproj pour appliquer la copie d'assemblys NuGet à la sortie de construction:

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Cependant, notez que la sortie de construction ( bin/Release/netcoreapp*/*) n'est pas censée être portable et distribuable, la sortie de dotnet publishest. Mais dans votre cas, la copie des assemblys dans la sortie de construction est probablement très utile à des fins de test. Mais notez que vous pouvez également utiliser l' DependencyContextAPI pour résoudre les DLL et leurs emplacements qui font partie du graphique de dépendance de l'application au lieu d'énumérer un répertoire local.

Martin Ullrich
la source
7
Cela provoque la copie de toutes les dll, pas seulement des dll Nuget
Mohammad Dayyan
2
Core 2 Je reçois également toutes les DLL Microsoft. Je ne sais pas pourquoi, mais avant de recevoir NuGet uniquement, mais il a cessé de le faire? ennuyeux
Piotr Kula
4
@MartinUllrich Pouvez-vous élaborer sur le DependencyContext? Comment puis-je l'utiliser pour trouver une DLL qui ne se trouve pas dans le répertoire de l'application? Où est-il de toute façon?
ygoe
2
ne fonctionne pas pour moi asp.net core ne copiant pas System.ValueTuple.dll
Ali Yousefi
1
@AliYousefie system.valuietuple pour les projets de framework .net ne devrait plus provenir de NuGet sur les versions récentes du framework .net et des outils de construction
Martin Ullrich
10

Vous pouvez utiliser PostBuildEvent pour automatiser le déploiement du module lors de la construction.

Pour obtenir des assemblys NuGet dans le dossier de construction, ajoutez csproj de votre module

<PropertyGroup>
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

Définissez les fichiers de module que vous souhaitez utiliser avec Inclure / Exclure (modifiez le chemin si nécessaire)

<ItemGroup>
    <ModuleFiles
      Include="$(TargetDir)*.dll"
      Exclude="$(TargetDir)System*.dll;$(TargetDir)Microsoft*.dll"
      DestinationPath="$(SolutionDir)src\MyProject\Modules\MyModule\%(Filename)%(Extension)">
    </ModuleFiles>
</ItemGroup>

Réinitialisez votre dossier de construction par défaut et ajoutez PostbuildEvent

<Target Name="PublishModule" AfterTargets="PostBuildEvent" Inputs="@(ModuleFiles)" Outputs="@(ModuleFiles->'%(DestinationPath)')">
    <WriteLinesToFile File="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
    <Copy SourceFiles="@(ModuleFiles)" DestinationFiles="@(ModuleFiles->'%(DestinationPath)')" />
    <Delete Files="$(SolutionDir)src\[YOURAPP]\app_offline.htm" />
</Target>

J'inclus app_offline pour recycler l'application si elle est déjà en cours d'exécution pour éviter les erreurs de fichier en cours d'utilisation.

Xeevis
la source
Dans mon projet, j'ai une dépendance sur la bibliothèque Nuget "Microsoft.Extensions.Logging.Log4Net.AspNetCore", et elle ne fait pas partie de NetCore, donc cette approche ne fonctionnera pas
sad_robot
4

Ajouter

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

n'a pas fonctionné, mais l'ajout de ceci au fichier .csproj Framework:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

fait.

Mike Brunner
la source
Cela a bien fonctionné pour moi lorsque je faisais référence aux bibliothèques .net Standard 2.0 à partir d'un projet .Net Framework 4.7.2. Rien d'autre ne l'a réparé.
Grungondola
3

J'ai "résolu" (créé une solution) ceci de manière plus simple.

En post build

dotnet publish "$(ProjectFileName)" --no-build -o pub
xcopy "$(ProjectDir)pub\3rdPartyProvider.*.dll" "$(OutDir)"

pub est le dossier dans lequel vous voulez que vos éléments publiés soient transférés

REMARQUE: selon la version que dotnet.exevous utilisez, la commande--no-build peut ne pas être disponible.

Par exemple, non disponible dans la v2.0.3; et disponible en v2.1.402. Je sais que VS2017 Update4 avait v2.0.3. Et Update8 a 2.1.x

Mettre à jour:

La configuration ci-dessus fonctionnera dans l'environnement de débogage de base, mais pour la mettre dans l'environnement de serveur / production de construction, il en faut plus. Dans cet exemple particulier que j'ai dû résoudre, nous construisons Release|x64et Release|x86séparément. J'ai donc pris en compte les deux. Mais pour prendre en charge la dotnet publishcommande post build , j'ai d'abord ajouté RuntimeIdentifierau fichier projet.

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
  <OutputPath>..\..\lib\</OutputPath>
  <RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
  <OutputPath>..\..\lib\</OutputPath>
  <RuntimeIdentifier>win-x86</RuntimeIdentifier>
</PropertyGroup>

Pourquoi j'en ai eu besoin et pourquoi vous pouvez vous en passer? J'en avais besoin car mon programme de construction est configuré pour intercepter l'avertissement MSB3270 et échouer la construction s'il apparaît. Cet avertissement dit: "hé, certains fichiers de vos dépendances sont de format incorrect". Mais vous souvenez-vous du but de cet exercice? Nous devons extraire les DLL de dépendance de package. Et dans de nombreux cas, cela n'a pas d'importance si cet avertissement est là, car après la construction de la publication ne se soucie pas. Encore une fois, c'est mon programme de construction qui se soucie. Donc, j'ai seulement ajoutéRuntimeIdentifier 2 configurations que j'utilise lors de la construction de production.

Version complète du post

if not exist "$(ProjectDir)obj\$(ConfigurationName)" mkdir "$(ProjectDir)obj\$(ConfigurationName)"
xcopy  "$(ProjectDir)obj\$(PlatformName)\$(ConfigurationName)" "$(ProjectDir)obj\$(ConfigurationName)" /E /R /Y

if $(ConfigurationName) == Release (
    dotnet publish "$(ProjectFileName)" --runtime win-$(PlatformName) --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
) else (
    dotnet publish "$(ProjectFileName)" --no-build -c $(ConfigurationName) -o pub --no-restore --no-dependencies
)

xcopy "$(ProjectDir)pub\my3rdPartyCompany.*.dll" "$(OutDir)" /Y /R

Explication: dotnet publish recherche obj\Debugou obj\Release. Nous ne l'avons pas pendant la construction car la compilation crée obj\x64\Releaseou obj\x86\Release. Les lignes 1 et 2 atténuent ce problème. Dans la ligne 3, je dis dotnet.exed'utiliser une configuration spécifique et un runtime cible. Sinon, quand c'est le mode de débogage, je ne me soucie pas des trucs d'exécution et des avertissements. Et dans la dernière ligne, je prends simplement mes dll et je les copie dans le dossier de sortie. Travail accompli.

TS
la source
Le paramètre "-c Release" est requis pour la commande "dotnet publish" si le projet n'a pas de configuration de débogage (comme dans mon cas). J'ai donc utilisé ce lot comme événement post-build: dotnet publish "$(ProjectFileName)" -c Release --no-build -o bin\pub xcopy "$(ProjectDir)pub\PostSharp.dll" "$(OutDir)"
Xtro
0

En conjonction avec la réponse ci-dessus: cela fonctionne très bien dans la ligne de commande de l'événement post-build: dans Visual Studio. Il boucle sur une sélection de dll (System * .dll et Microsoft .dll) *, puis ignore la suppression de dll spécifiques. System.Data.SqlClient.dll et System.Runtime.Loader.dll

for %%f in ($(OutDir)System*.dll $(OutDir)Microsoft*.dll) do if not %%f == $(OutDir)System.Data.SqlClient.dll if not %%f == $(OutDir)System.Runtime.Loader.dll del %%f
Loup de mer
la source