web-dev-qa-db-fra.com

Comment faire en sorte que les projets .NET Core copient les références NuGet pour générer la sortie?

J'essaie d'écrire un système de plug-in avec .NET Core, et l'une de mes exigences est de pouvoir distribuer le plug-in DLL avec ses dépendances pour l'utilisateur lors de l'installation. Cependant, je ne peux pas comprendre comment inclure mes dépendances NuGet en tant qu'artefact de construction et les exporter dans le dossier de génération, sans devoir utiliser dotnet publish en tant que piratage. Existe-t-il un moyen de spécifier cela dans le fichier csproj?

47
ron975

Vous pouvez ajouter ceci à un <PropertyGroup> dans votre fichier csproj pour appliquer la copie des assemblys NuGet à la sortie construite:

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Cependant, notez que la sortie de la construction (bin/Release/netcoreapp*/*) n'est pas supposée être portable et distribuable, la sortie de dotnet publish l'est. Mais dans votre cas, la copie des assemblys vers la sortie de génération est probablement très utile à des fins de test. Notez toutefois que vous pouvez également utiliser l'API DependencyContext pour résoudre les DLL et leurs emplacements faisant partie du graphe de dépendance de l'application au lieu d'énumérer un répertoire local.

82
Martin Ullrich

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

Pour obtenir les 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 voulez où utiliser Include/Exclude (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éinitialiser votre dossier de construction à la valeur par défaut et ajouter 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 d'utilisation du fichier.

7
Xeevis

Ajouter

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

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

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

fait.

3
Mike Brunner

J'ai "résolu" (créé le travail autour) ceci d'une manière plus simple.

En post construction

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

pub est le dossier dans lequel vous voulez que vos contenus publiés soient stockés

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

Par exemple, non disponible dans la version 2.0.3; et disponible dans 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 il est nécessaire d’en disposer davantage dans un environnement de production/serveur de génération. Dans cet exemple particulier que j'ai dû résoudre, nous construisons Release|x64 et Release|x86 séparément. J'ai donc pris en compte les deux. Mais pour prendre en charge la commande post build dotnet publish, j’ai d’abord ajouté RuntimeIdentifier au fichier de 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 avais besoin et pourquoi vous pouvez vous en passer? J'avais besoin de cela parce que mon programme de construction est configuré pour intercepter l'avertissement MSB3270 et qu'il échoue si la construction apparaît. Cet avertissement indique "hé, certains fichiers de vos dépendances ont un format incorrect". Mais vous souvenez-vous du but de cet exercice? Nous devons extraire les DLL de dépendance des paquets. Et dans de nombreux cas, l’avertissement n’est pas important, car il est indifférent après la construction. Encore une fois, c’est mon programme de construction qui tient à cœur. Ainsi, j’ai seulement ajouté RuntimeIdentifier à 2 configurations que j’utilise lors de la production.

Full Post build

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: La publication de dotnet recherche obj\Debug ou obj\Release. Nous ne l'avons pas pendant la construction parce que build crée obj\x64\Release ou obj\x86\Release. Les lignes 1 et 2 atténuent ce problème. À la ligne 3, je dis à dotnet.exe d'utiliser une configuration spécifique et un environnement d'exécution cible. Sinon, quand il s'agit du mode débogage, je ne me soucie pas des choses d'exécution et des avertissements. Et dans la dernière ligne, je prends simplement mes dlls et les copie ensuite dans le dossier de sortie. Travail accompli.

0
T.S.

En conjonction avec la réponse ci-dessus: Cela fonctionne très bien dans la ligne de commande d’événement post-construction: dans Visual Studio . Elle effectue une boucle sur une sélection de dlls (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
0
seabass