In che modo è possibile ottenere progetti .NET Core per copiare i riferimenti NuGet nell'output di compilazione?


111

Sto cercando di scrivere un sistema di plugin con .NET Core e uno dei miei requisiti è essere in grado di distribuire la DLL del plugin insieme alle sue dipendenze all'utente per l'installazione.

Tuttavia, non riesco a capire come includere le mie dipendenze NuGet come artefatto di build e averle in output nella cartella di build, senza doverle usare dotnet publishcome hack. C'è un modo per specificarlo nel file .csproj (file di progetto)?


2
Perché usare dotnet publishsarebbe un hack? Includere il comando nel file csproj come script di post build.
Austin Drenski

3
dotnet publishgetta l'intero framework nella cartella di pubblicazione, poiché sto scrivendo un plugin, la maggior parte dei file non sono necessari poiché il framework sarebbe già caricato dal programma bootstrapper. Sto cercando qualcosa di simile a come funzionano le build su .NET Framework.
chyyran

E includere <CopyToOutputDirectory>Always</CopyToOutputDirectory>nel tuo csproj su ciascuna delle DLL che vuoi spostare non fa il trucco? Forse combinato con un <link>nodo?
Austin Drenski

7
<PackageReference/>non supporta <CopyToOutputDirectory>.
chyyran

1
L '"intero framework" proviene da NuGet però .. e se scegli di copiare tutti gli assembly NuGet nell'output di compilazione, li otterrai tutti ..
Martin Ullrich

Risposte:


179

Puoi aggiungerlo a un <PropertyGroup>file csproj interno per imporre la copia di assembly NuGet nell'output di compilazione:

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Tuttavia, si noti che l'output di compilazione ( bin/Release/netcoreapp*/*) non dovrebbe essere portabile e distribuibile, l'output di dotnet publishè. Ma nel tuo caso, la copia degli assembly nell'output di build è probabilmente molto utile per scopi di test. Si noti, tuttavia, che è anche possibile utilizzare l' DependencyContextAPI per risolvere le DLL e le relative posizioni che fanno parte del grafico delle dipendenze dell'applicazione invece di enumerare una directory locale.


7
Fa copiare tutte le DLL, non solo le DLL Nuget
Mohammad Dayyan

2
Core 2 Ricevo anche tutte le DLL di Microsoft. Non sei sicuro del perché, ma prima stavo ottenendo solo NuGet ma poi ha smesso di farlo? fastidioso
Piotr Kula

4
@MartinUllrich Puoi approfondire il DependencyContext? Come posso usarlo per trovare una DLL che non si trova nella directory dell'applicazione? Dov'è comunque?
ygoe

2
non funziona per me asp.net core non copia System.ValueTuple.dll
Ali Yousefi

1
@AliYousefie system.valuietuple per progetti .net framework non dovrebbe più provenire da NuGet nelle recenti versioni .net framework e strumenti di compilazione
Martin Ullrich

10

È possibile utilizzare PostBuildEvent per automatizzare la distribuzione del modulo in build.

Per ottenere gli assembly NuGet nella cartella build, aggiungere in csproj del modulo

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

Definisci quali file di modulo vuoi dove usare Includi / Escludi (modifica il percorso se necessario)

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

Ripristina la cartella di build predefinita e aggiungi 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>

Includo app_offline per riciclare l'app se è già in esecuzione per evitare errori di utilizzo del file.


Nel mio progetto, ho una dipendenza dalla libreria Nuget "Microsoft.Extensions.Logging.Log4Net.AspNetCore" e non fa parte di NetCore, quindi questo approccio non funzionerà
sad_robot

4

Aggiunta

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

non ha funzionato, ma aggiungendolo al file Framework .csproj:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

fatto.


Questo ha funzionato bene per me quando facevo riferimento alle librerie .net Standard 2.0 da un progetto .Net Framework 4.7.2. Nient'altro lo ha risolto.
Grungondola

3

Ho "risolto" (creato una soluzione) questo in modo più semplice.

In post build

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

pub è la cartella in cui vuoi che le tue cose pubblicate vengano messe in scena

NOTA: a seconda della versione dotnet.exeutilizzata, il comando --no-buildpotrebbe non essere disponibile.

Ad esempio, non disponibile nella v2.0.3; e disponibile in v2.1.402. So che VS2017 Update4 aveva v2.0.3. E Update8 ha 2.1.x

Aggiornare:

La configurazione di cui sopra funzionerà nell'ambiente di debug di base, ma per metterla nel server di compilazione / ambiente di produzione è necessario di più. In questo particolare esempio che ho dovuto risolvere, costruiamo Release|x64e Release|x86separatamente. Quindi ho tenuto conto di entrambi. Ma per supportare il dotnet publishcomando post build , ho prima aggiunto RuntimeIdentifieral file di progetto.

<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>

Perché ne avevo bisogno e perché puoi farcela senza? Ne avevo bisogno perché il mio programma di compilazione è impostato per intercettare l'avviso MSB3270 e fallire la compilazione se viene visualizzato. Questo avviso dice "ehi, alcuni file nelle tue dipendenze hanno un formato sbagliato". Ma ricordi l'obiettivo di questo esercizio? Dobbiamo estrarre le DLL delle dipendenze dei pacchetti. E in molti casi non importa se questo avviso è presente perché dopo la compilazione del post non interessa. Ancora una volta, questo è il mio programma di compilazione che si preoccupa. Quindi, ho aggiunto solo RuntimeIdentifiera 2 configurazioni che uso durante la build di produzione.

Creazione post completa

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

Spiegazione: dotnet publish sta cercando obj\Debugo obj\Release. Non lo abbiamo durante la compilazione perché build crea obj\x64\Releaseo obj\x86\Release. Le righe 1 e 2 attenuano questo problema. Nella riga 3 dico dotnet.exedi utilizzare la configurazione specifica e il runtime di destinazione. Altrimenti, quando questa è la modalità di debug, non mi interessano le cose e gli avvisi di runtime. E nell'ultima riga prendo semplicemente i miei dll e li copio nella cartella di output. Lavoro fatto.


Il parametro "-c Release" è richiesto per il comando "dotnet publish" se il progetto non ha una configurazione di debug (come nel mio caso). Quindi ho usato questo batch come evento post-build: dotnet publish "$(ProjectFileName)" -c Release --no-build -o bin\pub xcopy "$(ProjectDir)pub\PostSharp.dll" "$(OutDir)"
Xtro

0

Insieme alla risposta di cui sopra: ho funzionato alla grande nella riga di comando dell'evento post-build: in Visual Studio. Esegue il ciclo su una selezione di dll (System * .dll e Microsoft .dll) *, quindi salta l'eliminazione di dll specifiche. System.Data.SqlClient.dll e 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.