Distribuzione a file singolo
La creazione di bundle di tutti i file dipendenti dall'applicazione in un singolo file binario offre agli sviluppatori di applicazioni l'opzione interessante di implementare e distribuire l'applicazione come file singolo. La distribuzione a file singolo è disponibile sia per il modello di distribuzione dipendente dal framework che per le applicazioni autonome.
Le dimensioni del file singolo in un'applicazione autonoma sono elevate perché includono il runtime e le librerie del framework. In .NET 6 è possibile pubblicare file trimmed per ridurre le dimensioni totali delle applicazioni compatibili con trim. L'opzione di distribuzione di un file singolo può essere combinata con le opzioni di pubblicazione ReadyToRun e Trim.
Importante
Per eseguire una singola app file in Windows 7, è necessario usare .NET Runtime 6.0.3 o versione successiva.
File di progetto di esempio
Ecco un file di progetto di esempio che specifica la pubblicazione di un file singolo:
<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>
Queste proprietà hanno le funzioni seguenti:
PublishSingleFile
. Abilita la pubblicazione a file singolo. Abilita inoltre gli avvisi di un file singolo durantedotnet build
.SelfContained
. Determina se l'applicazione è indipendente o dipendente dal framework.RuntimeIdentifier
. Specifica il sistema operativo e il tipo di CPU di destinazione. Imposta anche<SelfContained>true</SelfContained>
come impostazione predefinita.
Le applicazioni a file singolo sono sempre specifiche del sistema operativo e dell'architettura. È necessario pubblicare per ogni configurazione, ad esempio Linux x64, Linux Arm64, Windows x64 e così via.
I file di configurazione di esecuzione, ad esempio *.runtimeconfig.json e *.deps.json, sono inclusi nel file singolo.
Pubblicare un'applicazione a file singolo
Pubblicare una applicazione a file singolo usando il comando dotnet publish.
Aggiungere
<PublishSingleFile>true</PublishSingleFile>
al file di progetto.Questa modifica produce una applicazione a file singolo nella pubblicazione autonoma. Vengono inoltre visualizzati avvisi di compatibilità dei file singoli durante la compilazione.
<PropertyGroup> <PublishSingleFile>true</PublishSingleFile> </PropertyGroup>
Pubblicare l'app per un identificatore di runtime specifico usando
dotnet publish -r <RID>
L'esempio seguente pubblica l'applicazione per Windows come applicazione a file singolo indipendente.
dotnet publish -r win-x64
L'esempio seguente pubblica l'applicazione per Linux come applicazione a file singolo dipendente dal framework.
dotnet publish -r linux-x64 --self-contained false
<PublishSingleFile>
deve essere impostato nel file di progetto per abilitare l'analisi dei file durante la compilazione, ma è anche possibile trasmettere queste opzioni come argomenti dotnet publish
:
dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained false
Per altre informazioni, vedere Pubblicare applicazioni .NET Core con l'interfaccia della riga di comando di .NET.
Escludere i file dall'incorporamento
Alcuni file possono essere esclusi in modo esplicito dall'incorporazione nel file singolo impostando i metadati seguenti:
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
Ad esempio, per inserire alcuni file nella directory di pubblicazione, ma non aggregarli nel file:
<ItemGroup>
<Content Update="Plugin.dll">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
Includere file PDB all'interno del bundle
Il file PDB per un assembly può essere incorporato nell'assembly stesso (il .dll
) usando l'impostazione seguente. Poiché i simboli sono parte dell'assembly, essi fanno parte anche dell'applicazione:
<DebugType>embedded</DebugType>
Ad esempio, aggiungere la proprietà seguente al file di progetto di un assembly per incorporare il file PDB in tale assembly:
<PropertyGroup>
<DebugType>embedded</DebugType>
</PropertyGroup>
Altre considerazioni
Le applicazioni a file singolo hanno tutti i file PDB correlati insieme all'applicazione, non aggregati per impostazione predefinita. Se si desidera includere i PDB all'interno dell'assembly per i progetti compilati, impostare DebugType
su embedded
. Vedere Includere file PDB all'interno del pacchetto.
I componenti C++ gestiti non sono adatti per la distribuzione di file singoli. È consigliabile scrivere applicazioni in C# o in un altro linguaggio C++ non gestito perché siano compatibili con un file singolo,
Librerie native
Solo le DLL gestite vengono aggregate con l'applicazione in un file singolo eseguibile. All'avvio dell'applicazione, le DLL gestite vengono estratte e caricate in memoria, evitando l'estrazione in una cartella. Con questo approccio, i file binari gestiti sono incorporati nel bundle di file singolo, ma i file binari nativi del runtime principale sono file separati.
Per incorporare tali file per l'estrazione e ottenere un file di output, impostare la proprietà IncludeNativeLibrariesForSelfExtract
su true
.
Specificare che IncludeAllContentForSelfExtract
estrae tutti i file, inclusi gli assembly gestiti, prima di eseguire il file eseguibile. Ciò può essere utile per rari problemi di compatibilità delle applicazioni.
Importante
Se viene usata l'estrazione, i file vengono estratti su disco prima dell'avvio dell'applicazione:
- Se la variabile di ambiente
DOTNET_BUNDLE_EXTRACT_BASE_DIR
è impostata su un percorso, i file vengono estratti in una directory in tale percorso. - In caso contrario, se in esecuzione in Linux o macOS, i file vengono estratti in una directory in
$HOME/.net
. - Se in esecuzione in Windows, i file vengono estratti in una directory in
%TEMP%/.net
.
Per evitare manomissioni, tali directory non devono essere scrivibili da utenti o servizi con privilegi diversi. Non usare /tmp o /var/tmp nella maggior parte dei sistemi Linux e macOS.
Nota
In alcuni ambienti Linux, ad esempio in systemd
, l'estrazione predefinita non funziona perché $HOME
non è definita. In questi casi, è consigliabile impostare $DOTNET_BUNDLE_EXTRACT_BASE_DIR
in modo esplicito.
Per systemd
, una buona alternativa consiste nel definire DOTNET_BUNDLE_EXTRACT_BASE_DIR
nel proprio file di unità del servizio come %h/.net
, che systemd
si espande correttamente in $HOME/.net
per l'account che esegue il servizio.
[Service]
Environment="DOTNET_BUNDLE_EXTRACT_BASE_DIR=%h/.net"
Incompatibilità dell'API
Alcune API non sono compatibili con la distribuzione di file singoli. Le applicazioni potrebbero richiedere modifiche se utilizzano queste API. Se si usa un framework o un pacchetto di terze parti, è possibile che venga utilizzata una di queste API e richiedano modifiche. La causa più comune dei problemi è la dipendenza dai percorsi dei file per file o DLL fornite con l'applicazione.
La tabella seguente contiene i dettagli dell'API della libreria di runtime pertinente per l'uso di un file singolo.
API | Nota |
---|---|
Assembly.CodeBase |
Genera l'eccezione PlatformNotSupportedException. |
Assembly.EscapedCodeBase |
Genera l'eccezione PlatformNotSupportedException. |
Assembly.GetFile |
Genera l'eccezione IOException. |
Assembly.GetFiles |
Genera l'eccezione IOException. |
Assembly.Location |
Restituisce una stringa vuota. |
AssemblyName.CodeBase |
Restituisce null . |
AssemblyName.EscapedCodeBase |
Restituisce null . |
Module.FullyQualifiedName |
Restituisce una stringa con il valore <Unknown> o genera un'eccezione. |
Marshal.GetHINSTANCE |
Restituisce -1. |
Module.Name |
Restituisce una stringa con il valore <Unknown> . |
Sono disponibili alcuni consigli per la correzione di scenari comuni:
Per accedere ai file accanto al file eseguibile, usare AppContext.BaseDirectory.
Per trovare il nome file dell'eseguibile, usare il primo elemento di Environment.GetCommandLineArgs() o, a partire da .NET 6, usare il nome del file da ProcessPath.
Per evitare di distribuire esclusivamente file separati, è consigliabile usare le risorse incorporate.
Post-elaborazione di file binari prima della creazione di bundle
Alcuni flussi di lavoro richiedono la post-elaborazione dei file binari prima della creazione di bundle. Un esempio comune è la firma. La dotnet SDK fornisce punti di estensione MSBuild per consentire l'elaborazione di file binari appena prima della creazione di bundle a file singolo. Le API disponibili sono:
- La destinazione
PrepareForBundle
che verrà chiamata primaGenerateSingleFileBundle
- Un oggetto
<ItemGroup><FilesToBundle /></ItemGroup>
contenente tutti i file che verranno raggruppati - Una proprietà
AppHostFile
che specifica il modello apphost. La post-elaborazione potrebbe voler escludere l'apphost dall'elaborazione.
Per eseguire questa operazione, è necessario creare una destinazione che verrà eseguita tra PrepareForBundle
e GenerateSingleFileBundle
.
Si consideri l'esempio di nodo del progetto .NET seguente Target
:
<Target Name="MySignedBundledFile" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle">
È possibile che gli strumenti debbano copiare i file nel processo di firma. Ciò può verificarsi se il file originale è un elemento condiviso non di proprietà della compilazione, ad esempio il file proviene da una cache NuGet. In questo caso, è previsto che lo strumento modifichi il percorso dell'elemento corrispondente FilesToBundle
in modo che punti alla copia modificata.
Comprimere gli assembly nelle applicazioni a file singolo
Le applicazioni a file singolo possono essere create con la compressione abilitata negli assembly incorporati. Impostare la proprietà EnableCompressionInSingleFile
su true
. Il file singolo prodotto avrà tutti gli assembly incorporati compressi, cosa che può ridurre significativamente le dimensioni del file eseguibile.
La compressione include un costo delle prestazioni. All'avvio dell'applicazione, gli assembly devono essere decompressi in memoria, operazione che richiede tempo. È consigliabile misurare sia la modifica delle dimensioni sia il costo di avvio per abilitare la compressione prima di usarla. L'impatto può variare in modo significativo tra applicazioni diverse.
Esaminare un'applicazione a file singolo
Le applicazioni a file singolo possono essere esaminate usando lo strumento ILSpy. Lo strumento può visualizzare tutti i file in bundle nell'applicazione e può esaminare il contenuto degli assembly gestiti.