Bereitstellen einer einzelnen Datei

Wenn Sie alle Abhängigkeiten der Anwendung in eine einzelne Binärdatei packen, kann ein Anwendungsentwickler die Anwendung in einer Datei bereitstellen und verteilen. Die Einzeldateibereitstellung ist für das frameworkabhängige Bereitstellungsmodell sowie für eigenständige Anwendungen verfügbar.

Bei einer eigenständigen Anwendung handelt es sich dabei um eine große Datei, da die Runtime und die Frameworkbibliotheken enthalten sind. In .NET 6 können Sie gekürzt veröffentlichen, um die Gesamtgröße von kürzungskompatiblen Anwendungen zu reduzieren. Die Option zur Bereitstellung von Einzeldateien kann mit den Veröffentlichungsoptionen ReadyToRun und TRIM kombiniert werden.

Wichtig

Um eine Einzeldatei-App unter Windows 7 auszuführen, müssen Sie .NET Runtime 6.0.3 oder höher verwenden.

Beispielprojektdatei

Hier sehen Sie eine Beispielprojektdatei, in der die Veröffentlichung von Einzeldateien angegeben wird:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <PublishSingleFile>true</PublishSingleFile>
    <SelfContained>true</SelfContained>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
  </PropertyGroup>

</Project>

Diese Eigenschaften verfügen über die folgenden Funktionen:

  • PublishSingleFile. Aktiviert die Veröffentlichung von Einzeldateien. Aktiviert außerdem Einzeldateiwarnungen während dotnet build.
  • SelfContained Bestimmt, ob die App eigenständig oder frameworkabhängig ist.
  • RuntimeIdentifier. Gibt das Betriebssystem und den CPU-Typ an, die Sie als Ziel verwenden. <SelfContained>true</SelfContained> wird auch standardmäßig festgelegt.

Einzeldatei-Apps sind immer betriebssystem- und architekturspezifisch. Sie müssen für jede Konfiguration wie Linux x64, Linux ARM64, Windows x64 usw. eine App veröffentlichen.

Laufzeitkonfigurationsdateien, z. B. *.runtimeconfig.json und *.deps.json, sind in der Einzeldatei enthalten. Wenn eine zusätzliche Konfigurationsdatei benötigt wird, können Sie sie neben der Einzeldatei platzieren.

Veröffentlichen einer Einzeldatei-App

Sie können Ihre Einzeldatei-App mit dem Befehl dotnet publish veröffentlichen.

  1. Fügen Sie <PublishSingleFile>true</PublishSingleFile> zu Ihrer Projektdatei hinzu.

    Durch diese Änderung wird eine Einzeldatei-App bei einer eigenständigen Veröffentlichung erzeugt. Außerdem werden während der Erstellung Kompatibilitätswarnungen für einzelne Dateien angezeigt.

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>
    
  2. Veröffentlichen Sie die App für einen bestimmten Runtimebezeichner mit dotnet publish -r <RID>.

    Im folgenden Beispiel wird eine App für Windows als eigenständige Einzeldateianwendung veröffentlicht.

    dotnet publish -r win-x64

    Im folgenden Beispiel wird die App für Linux als frameworkabhängige Einzeldatei-App veröffentlicht.

    dotnet publish -r linux-x64 --self-contained false

<PublishSingleFile> sollte in der Projektdatei festgelegt werden, um die Analyse von Dateien während der Erstellung zu ermöglichen. Es ist aber auch möglich, diese Optionen als dotnet publish-Argumente zu übergeben:

dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained false

Weitere Informationen finden Sie unter Veröffentlichen von .NET Core-Apps mit der .NET-CLI.

Ausschließen von Dateien aus der Einbettung

Bestimmte Dateien können explizit aus der Einbettung in die Einzeldatei ausgeschlossen werden, indem Sie die folgenden Metadaten festlegen:

<ExcludeFromSingleFile>true</ExcludeFromSingleFile>

So können Sie beispielsweise einige Dateien im Veröffentlichungsverzeichnis speichern, ohne diese in die Datei zu packen:

<ItemGroup>
  <Content Update="Plugin.dll">
    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
  </Content>
</ItemGroup>

Einschließen von PDB-Dateien in das Bündel

Die PDB-Datei für eine Assembly kann mithilfe der folgenden Einstellung in die Assembly selbst (.dll) eingebettet werden. Da die Symbole Teil der Assembly sind, sind sie auch Teil der Anwendung:

<DebugType>embedded</DebugType>

Fügen Sie z. B. die folgende Eigenschaft in die Projektdatei einer Assembly ein, um die PDB-Datei in diese Assembly einzubetten:

<PropertyGroup>
  <DebugType>embedded</DebugType>
</PropertyGroup>

Weitere Überlegungen

Einzeldateianwendungen enthalten alle zugehörigen PDB-Dateien neben der Anwendung, die standardmäßig nicht zusammen gepackt sind. Wenn Sie PDBs in die Assembly für Projekte, die Sie erstellen, einschließen möchten, legen Sie den DebugType auf embedded fest. Siehe Einschließen von PDB-Dateien in das Paket.

Verwaltete C++-Komponenten eignen sich nicht gut für die Einzeldateibereitstellung. Es wird empfohlen, Anwendungen in C# oder einer anderen nicht verwalteten C++-Programmiersprache zu schreiben, wenn diese mit der Einzeldateibereitstellung kompatibel sein sollen.

Native Bibliotheken

Es werden nur verwaltete DLLs mit der App in eine einzelne ausführbare Datei gepackt. Beim Starten der App werden die verwalteten DLLs extrahiert und in den Arbeitsspeicher geladen. Das verhindert das Extrahieren in einen Ordner. Mit diesem Ansatz werden die verwalteten Binärdateien in das Einzeldateipaket eingebettet. Die nativen Binärdateien der Core-Runtime selbst werden jedoch als separate Dateien abgespeichert.

Um diese Dateien für die Extrahierung einzubetten und eine Ausgabedatei zu erhalten, legen Sie die Eigenschaft IncludeNativeLibrariesForSelfExtract auf true fest.

Wenn Sie IncludeAllContentForSelfExtract angeben, werden alle Dateien, einschließlich der verwalteten Assemblys, extrahiert, bevor die ausführbare Datei ausgeführt wird. Dies kann bei seltenen Kompatibilitätsproblemen von Anwendungen hilfreich sein.

Wichtig

Wenn Extraktion verwendet wird, werden die Dateien auf den Datenträger extrahiert, bevor die App gestartet wird:

  • Wenn die Umgebungsvariable DOTNET_BUNDLE_EXTRACT_BASE_DIR auf einen Pfad festgelegt ist, werden die Dateien in ein Verzeichnis unter diesem Pfad extrahiert.
  • Andernfalls werden die Dateien bei Ausführung unter Linux oder macOS in ein Verzeichnis unter $HOME/.net extrahiert.
  • Bei Ausführung unter Windows werden die Dateien in ein Verzeichnis unter %TEMP%/.net extrahiert.

Um Manipulationen zu verhindern, sollten Benutzer oder Dienste mit anderen Berechtigungen nicht in diese Verzeichnisse schreiben dürfen. Verwenden Sie weder /tmp noch /var/tmp auf den meisten Linux- und macOS-Systemen.

Hinweis

In einigen Linux-Umgebungen, z. B. unter systemd, funktioniert die Standardextrahierung nicht, da $HOME nicht definiert ist. In solchen Fällen wird empfohlen, explizit $DOTNET_BUNDLE_EXTRACT_BASE_DIR festzulegen.

Für systemd ist es eine gute Alternative, DOTNET_BUNDLE_EXTRACT_BASE_DIR in der Komponentendatei Ihres Diensts als %h/.net zu definieren, was systemd korrekt in $HOME/.net für das Konto erweitert, das den Dienst ausführt.

[Service]
Environment="DOTNET_BUNDLE_EXTRACT_BASE_DIR=%h/.net"

API-Inkompatibilität

Einige APIs sind nicht mit der Einzeldateibereitstellung kompatibel. Anwendungen müssen möglicherweise geändert werden, wenn sie diese APIs verwenden. Wenn Sie ein Framework oder ein Paket eines Drittanbieters verwenden, verwenden diese möglicherweise auch eine dieser APIs und müssen deshalb geändert werden. Die häufigste Ursache für Probleme ist die Abhängigkeit von Dateipfaden für Dateien oder DLLs, die im Lieferumfang der Anwendung enthalten sind.

Die folgende Tabelle enthält die Details zur relevanten Laufzeitbibliotheks-API für die Einzeldateiverwendung.

API Hinweis
Assembly.CodeBase Löst PlatformNotSupportedException aus.
Assembly.EscapedCodeBase Löst PlatformNotSupportedException aus.
Assembly.GetFile Löst IOException aus.
Assembly.GetFiles Löst IOException aus.
Assembly.Location Gibt eine leere Zeichenfolge zurück.
AssemblyName.CodeBase Gibt nullzurück.
AssemblyName.EscapedCodeBase Gibt nullzurück.
Module.FullyQualifiedName Diese API gibt eine Zeichenfolge mit dem Wert <Unknown> zurück oder löst eine Ausnahme aus.
Marshal.GetHINSTANCE Gibt -1 zurück.
Module.Name Diese API gibt eine Zeichenfolge mit dem Wert <Unknown>zurück.

Es gibt einige Empfehlungen zum Behandeln häufiger Szenarios:

Nachbearbeiten von Binärdateien vor der Bündelung

Einige Workflows erfordern die Nachbearbeitung von Binärdateien vor der Bündelung. Ein gängiges Beispiel ist das Signieren. Das dotnet SDK bietet MSBuild-Erweiterungspunkte, um die Verarbeitung von Binärdateien kurz vor der Einzeldateibündelung zu ermöglichen. Die verfügbaren APIs sind:

  • Ein Ziel-PrepareForBundle, das vor GenerateSingleFileBundle aufgerufen wird.
  • Eine <ItemGroup><FilesToBundle /></ItemGroup> mit allen Dateien, die gebündelt werden sollen.
  • Eine Eigenschaft AppHostFile, die die apphost-Vorlage angibt. Bei der Nachbearbeitung möchten Sie möglicherweise die apphost-Instanz von der Verarbeitung ausschließen.

Dazu müssen Sie ein Ziel erstellen, das zwischen PrepareForBundle und GenerateSingleFileBundle ausgeführt wird.

Betrachten Sie das folgende Target-Knotenbeispiel des .NET-Projekts:

<Target Name="MySignedBundledFile" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle">

Es ist möglich, dass das Tool beim Signieren Dateien kopieren muss. Das kann passieren, wenn die Originaldatei ein freigegebenes Element ist, das nicht zum Build gehört, wenn z. B. die Datei aus einem NuGet-Cache stammt. In einem solchen Fall wird erwartet, dass das Tool den Pfad des entsprechenden FilesToBundle-Elements so ändert, dass er auf die geänderte Kopie zeigt.

Komprimieren von Assemblys in Einzeldatei-Apps

Einzeldatei-Apps können mit aktivierter Komprimierung für die eingebetteten Assemblys erstellt werden. Setzen Sie die EnableCompressionInSingleFile-Eigenschaft auf true. In der erzeugten Einzeldatei sind alle eingebetteten Assemblys komprimiert, sodass die Größe der ausführbaren Datei erheblich reduziert werden kann.

Die Komprimierung geht auf Kosten der Leistung. Beim Anwendungsstart müssen die Assemblys im Arbeitsspeicher dekomprimiert werden, was einige Zeit in Anspruch nimmt. Es wird empfohlen, vor der Verwendung von Komprimierung sowohl die Größenänderung als auch die Startkosten für die Aktivierung der Komprimierung zu messen. Die Auswirkungen können zwischen den verschiedenen Anwendungen erheblich variieren.

Untersuchen einer Einzeldatei-App

Einzeldatei-Apps können mit dem ILSpy-Tool überprüft werden. Das Tool kann alle in der Anwendung gepackten Dateien anzeigen und den Inhalt verwalteter Assemblys untersuchen.

Siehe auch