Wie kann ich .NET Core-Projekte dazu bringen, NuGet-Verweise auf die Build-Ausgabe zu kopieren?

108

Ich versuche, ein Plugin-System mit .NET Core zu schreiben. Eine meiner Anforderungen besteht darin, die Plugin-DLL zusammen mit ihren Abhängigkeiten zur Installation an den Benutzer zu verteilen.

Ich kann jedoch nicht herausfinden, wie ich meine NuGet-Abhängigkeiten als Build-Artefakt einbinden und in den Build-Ordner ausgeben kann, ohne sie dotnet publishals Hack verwenden zu müssen. Gibt es eine Möglichkeit, dies in der .csproj-Datei (Projektdatei) anzugeben?

Chyyran
quelle
2
Warum sollte die Verwendung dotnet publishein Hack sein? Fügen Sie den Befehl als Post-Build-Skript in Ihre csproj-Datei ein.
Austin Drenski
3
dotnet publishwirft das gesamte Framework in den Publish-Ordner, da ich ein Plugin schreibe, sind die meisten Dateien nicht erforderlich, da das Framework bereits vom Bootstrapper-Programm geladen würde. Ich suche nach etwas Ähnlichem wie Builds unter .NET Framework.
Chyyran
Und <CopyToOutputDirectory>Always</CopyToOutputDirectory>das Einfügen in Ihr csproj in jede der DLLs, die Sie verschieben möchten, reicht nicht aus? Vielleicht mit einem <link>Knoten kombiniert ?
Austin Drenski
7
<PackageReference/>unterstützt nicht <CopyToOutputDirectory>.
Chyyran
1
Das "gesamte Framework" stammt jedoch von NuGet. Wenn Sie sich dafür entscheiden, alle NuGet-Assemblys in die Build-Ausgabe zu kopieren, erhalten Sie alle.
Martin Ullrich

Antworten:

177

Sie können dies zu einer <PropertyGroup>Datei in Ihrer csproj-Datei hinzufügen, um das Kopieren von NuGet-Assemblys in die Build-Ausgabe zu erzwingen:

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

Beachten Sie jedoch, dass die Build-Ausgabe ( bin/Release/netcoreapp*/*) nicht portabel und verteilbar sein soll, sondern die Ausgabe von dotnet publish. In Ihrem Fall ist das Kopieren der Assemblys in die Build-Ausgabe wahrscheinlich zu Testzwecken sehr nützlich. Beachten Sie jedoch, dass Sie die DependencyContextAPI auch verwenden können , um die DLLs und ihre Speicherorte aufzulösen, die Teil des Abhängigkeitsdiagramms der Anwendung sind, anstatt ein lokales Verzeichnis aufzulisten.

Martin Ullrich
quelle
7
Es bewirkt, dass alle DLLs kopiert werden, nicht nur Nuget-DLLs
Mohammad Dayyan,
2
Core 2 Ich bekomme auch alle Microsoft DLLs. Sie sind sich nicht sicher, warum, aber bevor ich nur NuGet bekam, aber dann hat es aufgehört? nervig
Piotr Kula
4
@MartinUllrich Kannst du das näher erläutern DependencyContext? Wie kann ich damit eine DLL finden, die sich nicht im Anwendungsverzeichnis befindet? Wo ist es überhaupt?
Ygoe
2
funktioniert nicht für mich asp.net Kern kopiert nicht System.ValueTuple.dll
Ali Yousefi
1
@AliYousefie system.valuietuple für .net Framework-Projekte sollte nicht mehr von NuGet auf aktuellen .net Framework-Versionen und Build-Tools stammen
Martin Ullrich
10

Mit PostBuildEvent können Sie die Modulbereitstellung beim Erstellen automatisieren.

Um NuGet-Assemblys in den Build-Ordner zu bringen, fügen Sie csproj Ihres Moduls hinzu

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

Definieren Sie mithilfe von Einschließen / Ausschließen, welche Moduldateien wo angezeigt werden sollen (ändern Sie den Pfad nach Bedarf).

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

Setzen Sie Ihren Build-Ordner auf den Standard zurück und fügen Sie PostbuildEvent hinzu

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

Ich füge app_offline hinzu, um die App zu recyceln, wenn sie bereits ausgeführt wird, um Fehler bei der Verwendung von Dateien zu vermeiden.

Xeevis
quelle
In meinem Projekt habe ich eine Abhängigkeit von der Nuget-Bibliothek "Microsoft.Extensions.Logging.Log4Net.AspNetCore" und sie ist nicht Teil von NetCore, daher funktioniert dieser Ansatz nicht
sad_robot
4

Hinzufügen

<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>

hat nicht funktioniert, aber dies zur Framework .csproj-Datei hinzugefügt:

<RestoreProjectStyle>PackageReference</RestoreProjectStyle>

tat.

Mike Brunner
quelle
Dies funktionierte gut für mich, als ich .net Standard 2.0-Bibliotheken aus einem .Net Framework 4.7.2-Projekt heraus referenzierte. Nichts anderes hat es behoben.
Grungondola
3

Ich habe dies auf einfachere Weise "gelöst" (umgangen).

In Post Build

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

pub ist der Ordner, in dem Ihre veröffentlichten Inhalte bereitgestellt werden sollen

HINWEIS: Je nachdem, welche Version dotnet.exeSie verwenden, ist der Befehl --no-buildmöglicherweise nicht verfügbar.

Zum Beispiel nicht verfügbar in v2.0.3; und verfügbar in v2.1.402. Ich weiß, dass VS2017 Update4 v2.0.3 hatte. Und Update8 hat 2.1.x.

Aktualisieren:

Das obige Setup funktioniert in der Basis-Debug-Umgebung, aber um es in die Build-Server- / Produktionsumgebung zu integrieren, ist mehr erforderlich. In diesem speziellen Beispiel, das ich lösen musste, bauen wir Release|x64und Release|x86getrennt. Also habe ich beides erklärt. Um den Post-Build- dotnet publishBefehl zu unterstützen, habe ich zuerst eine RuntimeIdentifierProjektdatei hinzugefügt .

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

Warum brauchte ich es und warum kannst du ohne es davonkommen? Ich brauchte dies, weil mein Build-Programm so eingestellt ist, dass es die Warnung MSB3270 abfängt und den Build fehlschlägt, wenn er angezeigt wird. Diese Warnung lautet: "Hey, einige Dateien in Ihren Abhängigkeiten haben ein falsches Format." Aber erinnern Sie sich an das Ziel dieser Übung? Wir müssen Paketabhängigkeits-DLLs ziehen. In vielen Fällen spielt es keine Rolle, ob diese Warnung vorhanden ist, da es nicht wichtig ist, dem Post-Build zu folgen. Auch dies ist mein Build-Programm, das sich interessiert. Daher habe ich nur RuntimeIdentifier2 Konfigurationen hinzugefügt , die ich während des Produktionsaufbaus verwende.

Vollständiger 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

Erläuterung: dotnet Publish sucht nach obj\Debugoder obj\Release. Wir haben es nicht während des Builds, weil Build erstellt obj\x64\Releaseoder obj\x86\Release. Zeile 1 und 2 mindern dieses Problem. In Zeile 3 fordere ich Sie dotnet.exeauf, eine bestimmte Konfiguration und Ziellaufzeit zu verwenden. Andernfalls, wenn dies der Debug-Modus ist, interessieren mich Laufzeitsachen und Warnungen nicht. Und in der letzten Zeile nehme ich einfach meine DLLs und kopiere sie dann in den Ausgabeordner. Job erledigt.

TS
quelle
Der Parameter "-c Release" ist für den Befehl "dotnet Publish" erforderlich, wenn das Projekt keine Debug-Konfiguration hat (wie in meinem Fall). Also habe ich diesen Stapel als Post-Build-Ereignis verwendet: dotnet publish "$(ProjectFileName)" -c Release --no-build -o bin\pub xcopy "$(ProjectDir)pub\PostSharp.dll" "$(OutDir)"
Xtro
0

In Verbindung mit der obigen Antwort: In der Befehlszeile für Post-Build-Ereignisse funktioniert dies hervorragend : in Visual Studio. Es durchläuft eine Auswahl von DLLs (System * .dll und Microsoft .dll) * und überspringt dann das Löschen bestimmter DLLs. System.Data.SqlClient.dll und 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
Seebarsch
quelle