Jak uzyskać projekty .NET Core w celu skopiowania odwołań NuGet do danych wyjściowych kompilacji?

112

Próbuję napisać system wtyczek z .NET Core, a jednym z moich wymagań jest możliwość dystrybucji biblioteki DLL wtyczki wraz z jej zależnościami do użytkownika w celu zainstalowania.

Nie mogę jednak dowiedzieć się, jak uwzględnić moje zależności NuGet jako artefakt kompilacji i umieścić je w folderze kompilacji bez konieczności użycia ich dotnet publishjako hackowania. Czy istnieje sposób, w jaki mogę to określić w pliku .csproj (pliku projektu)?

chyyran
źródło
2
Dlaczego używanie miałoby dotnet publishbyć włamaniem? Dołącz polecenie do pliku csproj jako skrypt po kompilacji.
Austin Drenski
3
dotnet publishwrzuca cały framework do folderu publikowania, ponieważ piszę wtyczkę, większość plików nie jest potrzebna, ponieważ framework byłby już załadowany przez program ładujący. Szukam czegoś podobnego do tego, jak działają kompilacje na .NET Framework.
chyyran
A włączenie <CopyToOutputDirectory>Always</CopyToOutputDirectory>w csproj każdej z bibliotek dll, które chcesz przenieść, nie załatwia sprawy? Może w połączeniu z <link>węzłem?
Austin Drenski
7
<PackageReference/>nie obsługuje <CopyToOutputDirectory>.
chyyran
1
„Cały framework” pochodzi jednak z NuGet .. i jeśli zdecydujesz się skopiować wszystkie zestawy NuGet do danych wyjściowych kompilacji, otrzymasz je wszystkie ..
Martin Ullrich

Odpowiedzi:

180

Możesz dodać to do pliku <PropertyGroup>wewnątrz pliku csproj, aby wymusić kopiowanie zestawów NuGet do danych wyjściowych kompilacji:

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Należy jednak pamiętać, że wynik kompilacji ( bin/Release/netcoreapp*/*) nie powinien być przenośny i dystrybuowalny, wynik dotnet publishjest. Ale w twoim przypadku kopiowanie zestawów do danych wyjściowych kompilacji jest prawdopodobnie bardzo przydatne do celów testowych. Należy jednak pamiętać, że można również użyć DependencyContextinterfejsu API do rozwiązywania bibliotek DLL i ich lokalizacji, które są częścią wykresu zależności aplikacji, zamiast wyliczać katalog lokalny.

Martin Ullrich
źródło
7
Powoduje kopiowanie wszystkich bibliotek dll, a nie tylko bibliotek Nuget
Mohammad Dayyan
2
Core 2 Otrzymuję też wszystkie biblioteki DLL firmy Microsoft. Nie wiem, dlaczego, ale zanim otrzymałem tylko NuGet, ale potem przestał to robić? irytujące
Piotr Kula
4
@MartinUllrich Czy możesz rozwinąć temat DependencyContext? Jak mogę go użyć, aby znaleźć bibliotekę DLL, której nie ma w katalogu aplikacji? Gdzie to w ogóle jest?
ygoe
2
nie działa dla mnie rdzeń asp.net nie kopiuje System.ValueTuple.dll
Ali Yousefi
1
@AliYousefie system.valuietuple dla projektów platformy .NET nie powinno już pochodzić z NuGet w najnowszych wersjach platformy .NET i narzędzi do kompilacji
Martin Ullrich
10

Możesz użyć PostBuildEvent, aby zautomatyzować wdrażanie modułów podczas kompilacji.

Aby uzyskać zestawy NuGet w folderze kompilacji, dodaj csproj modułu

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

Zdefiniuj, które pliki modułów chcesz, gdzie przy użyciu Uwzględnij / Wyklucz (zmodyfikuj ścieżkę w razie potrzeby)

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

Zresetuj folder kompilacji do domyślnego i dodaj 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>

Dołączam app_offline do recyklingu aplikacji, jeśli jest już uruchomiona, aby uniknąć błędów w użyciu plików.

Xeevis
źródło
W moim projekcie mam zależność od biblioteki Nuget „Microsoft.Extensions.Logging.Log4Net.AspNetCore” i nie jest ona częścią NetCore, więc to podejście nie zadziała
sad_robot
4

Dodawanie

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

nie zadziałało, ale dodanie tego do pliku .csproj Framework:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

zrobił.

Mike Brunner
źródło
Działało to dobrze, gdy odwoływałem się do bibliotek .net Standard 2.0 z projektu .Net Framework 4.7.2. Nic innego tego nie naprawiło.
Grungondola
3

„Rozwiązałem” to (stworzyłem obejście) w prostszy sposób.

W budowaniu postu

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

pub jest folderem, w którym chcesz umieścić swoje opublikowane rzeczy na postoju

UWAGA: w zależności od używanej wersji dotnet.exe, polecenie--no-build może nie być dostępne.

Na przykład niedostępne w wersji 2.0.3; i dostępny w wersji 2.1.402. Wiem, że VS2017 Update4 miał v2.0.3. A Update8 ma 2.1.x

Aktualizacja:

Powyższa konfiguracja będzie działać w podstawowym środowisku debugowania, ale aby umieścić ją w środowisku serwera kompilacji / środowisku produkcyjnym, potrzeba więcej. W tym konkretnym przykładzie, który musiałem rozwiązać, budujemy Release|x64i Release|x86osobno. Więc rozliczyłem się z obu. Aby jednak obsługiwać polecenie po kompilacji dotnet publish, najpierw dodałem RuntimeIdentifierdo pliku projektu.

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

Dlaczego tego potrzebowałem i dlaczego możesz się bez niego obejść? Potrzebowałem tego, ponieważ mój program kompilacji jest ustawiony na przechwytywanie ostrzeżenia MSB3270 i niepowodzenie kompilacji, jeśli się pojawi. To ostrzeżenie mówi: „Hej, niektóre pliki w Twoich zależnościach mają niewłaściwy format”. Ale czy pamiętasz cel tego ćwiczenia? Musimy pobrać biblioteki DLL zależności pakietów. W wielu przypadkach nie ma znaczenia, czy jest to ostrzeżenie, ponieważ po kompilacji nie obchodzi. Ponownie, to jest mój program do kompilacji, który dba. Więc dodałem tylko RuntimeIdentifier2 konfiguracje, których używam podczas kompilacji produkcyjnej.

Pełna kompilacja postu

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

Objaśnienie: dotnet Publishing wyszukuje obj\Debuglub obj\Release. Nie mamy tego podczas kompilacji, ponieważ build tworzy obj\x64\Releaselub obj\x86\Release. Wiersze 1 i 2 łagodzą ten problem. W linii 3 mówię, dotnet.exeaby użyć określonej konfiguracji i docelowego środowiska wykonawczego. W przeciwnym razie, gdy jest to tryb debugowania, nie obchodzą mnie rzeczy i ostrzeżenia w czasie wykonywania. W ostatniej linii po prostu pobieram moje biblioteki dll i kopiuję je do folderu wyjściowego. Zadanie wykonane.

TS
źródło
Parametr „-c Release” jest wymagany dla polecenia „dotnet Publishing”, jeśli projekt nie ma konfiguracji debugowania (jak w moim przypadku). Więc użyłem tej partii jako wydarzenia post-build: dotnet publish "$(ProjectFileName)" -c Release --no-build -o bin\pub xcopy "$(ProjectDir)pub\PostSharp.dll" "$(OutDir)"
Xtro
0

W połączeniu z powyższą odpowiedzią: Mam to doskonale działające w wierszu poleceń zdarzenia po kompilacji: w Visual Studio. Pętla obejmuje wybrane biblioteki DLL (System * .dll i Microsoft .dll) *, a następnie pomija usuwanie określonych bibliotek DLL. System.Data.SqlClient.dll i 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
labraks
źródło