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ährenddotnet 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.
Veröffentlichen einer Einzeldatei-App
Sie können Ihre Einzeldatei-App mit dem Befehl dotnet publish veröffentlichen.
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>
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 null zurück. |
AssemblyName.EscapedCodeBase |
Gibt null zurü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:
Verwenden Sie AppContext.BaseDirectory, um auf Dateien neben der ausführbaren Datei zuzugreifen.
Um den Dateinamen der ausführbaren Datei zu finden, verwenden Sie das erste Element von Environment.GetCommandLineArgs(), oder verwenden Sie ab .NET 6 den Dateinamen aus ProcessPath.
Verwenden Sie die eingebetteten Ressourcen, um das Versenden loser Dateien zu vermeiden.
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 vorGenerateSingleFileBundle
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.