Implantação de arquivo único
A agregação de todos os arquivos dependentes do aplicativo em um único binário fornece ao desenvolvedor de aplicativos a opção atraente de implantar e distribuir o aplicativo como um único arquivo. A implantação de arquivo único está disponível tanto para o modelo de implantação dependente da estrutura quanto para aplicativos autônomos.
O tamanho do arquivo único em um aplicativo autônomo é grande, pois inclui o tempo de execução e as bibliotecas de estrutura. No .NET 6, você pode publicar cortado para reduzir o tamanho total de aplicativos compatíveis com corte. A opção de implantação de arquivo único pode ser combinada com as opções de publicação ReadyToRun e Trim .
Importante
Para executar um aplicativo de arquivo único no Windows 7, você deve usar o .NET Runtime 6.0.3 ou posterior.
Arquivo de projeto de exemplo
Aqui está um arquivo de projeto de exemplo que especifica a publicação de arquivo único:
<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>
Estas propriedades têm as seguintes funções:
PublishSingleFile
. Permite a publicação de um único arquivo. Também permite avisos de arquivo único durantedotnet build
o .SelfContained
. Determina se o aplicativo é autônomo ou dependente da estrutura.RuntimeIdentifier
. Especifica o sistema operacional e o tipo de CPU que você está segmentando. Também define<SelfContained>true</SelfContained>
por padrão.
Os aplicativos de arquivo único são sempre específicos do sistema operacional e da arquitetura. Você precisa publicar para cada configuração, como Linux x64, Linux Arm64, Windows x64 e assim por diante.
Os arquivos de configuração de tempo de execução, como *.runtimeconfig.json e *.deps.json, são incluídos no arquivo único.
Publicar um aplicativo de arquivo único
Publique um aplicativo de arquivo único usando o comando dotnet publishing .
Adicione
<PublishSingleFile>true</PublishSingleFile>
ao seu arquivo de projeto.Essa alteração produz um único aplicativo de arquivo na publicação independente. Ele também mostra avisos de compatibilidade de arquivo único durante a compilação.
<PropertyGroup> <PublishSingleFile>true</PublishSingleFile> </PropertyGroup>
Publique o aplicativo para um identificador de tempo de execução específico usando
dotnet publish -r <RID>
O exemplo a seguir publica o aplicativo para Windows como um aplicativo de arquivo único independente.
dotnet publish -r win-x64
O exemplo a seguir publica o aplicativo para Linux como um aplicativo de arquivo único dependente da estrutura.
dotnet publish -r linux-x64 --self-contained false
<PublishSingleFile>
deve ser definido no arquivo de projeto para habilitar a análise de arquivo durante a compilação, mas também é possível passar essas opções como dotnet publish
argumentos:
dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained false
Para obter mais informações, consulte Publicar aplicativos .NET Core com .NET CLI.
Excluir arquivos da incorporação
Determinados arquivos podem ser explicitamente excluídos de serem incorporados no arquivo único, definindo os seguintes metadados:
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
Por exemplo, para colocar alguns arquivos no diretório de publicação, mas não agrupá-los no arquivo:
<ItemGroup>
<Content Update="Plugin.dll">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
Incluir arquivos PDB dentro do pacote
O arquivo PDB para um assembly pode ser incorporado no próprio assembly (o .dll
) usando a configuração abaixo. Como os símbolos fazem parte da montagem, eles também fazem parte do aplicativo:
<DebugType>embedded</DebugType>
Por exemplo, adicione a seguinte propriedade ao arquivo de projeto de um assembly para incorporar o arquivo PDB a esse assembly:
<PropertyGroup>
<DebugType>embedded</DebugType>
</PropertyGroup>
Outras considerações
Os aplicativos de arquivo único têm todos os arquivos PDB relacionados ao lado do aplicativo, não agrupados por padrão. Se você quiser incluir PDBs dentro do assembly para projetos que você cria, defina como DebugType
embedded
. Consulte Incluir arquivos PDB dentro do pacote.
Os componentes C++ gerenciados não são adequados para a implantação de um único arquivo. Recomendamos que você escreva aplicativos em C# ou outra linguagem C++ não gerenciada para ser compatível com um único arquivo.
Bibliotecas nativas
Somente DLLs gerenciadas são agrupadas com o aplicativo em um único executável. Quando o aplicativo é iniciado, as DLLs gerenciadas são extraídas e carregadas na memória, evitando a extração para uma pasta. Com essa abordagem, os binários gerenciados são incorporados no pacote de arquivo único, mas os binários nativos do próprio tempo de execução principal são arquivos separados.
Para incorporar esses arquivos para extração e obter um arquivo de saída, defina a propriedade IncludeNativeLibrariesForSelfExtract
como true
.
A especificação IncludeAllContentForSelfExtract
extrai todos os arquivos, incluindo os assemblies gerenciados, antes de executar o executável. Isso pode ser útil para problemas raros de compatibilidade de aplicativos.
Importante
Se a extração for usada, os arquivos serão extraídos para o disco antes que o aplicativo seja iniciado:
- Se a
DOTNET_BUNDLE_EXTRACT_BASE_DIR
variável de ambiente for definida como um caminho, os arquivos serão extraídos para um diretório sob esse caminho. - Caso contrário, se estiver sendo executado no Linux ou macOS, os arquivos serão extraídos para um diretório em
$HOME/.net
. - Se estiver sendo executado no Windows, os arquivos são extraídos para um diretório em
%TEMP%/.net
.
Para evitar adulterações, esses diretórios não devem ser graváveis por usuários ou serviços com privilégios diferentes. Não use /tmp ou /var/tmp na maioria dos sistemas Linux e macOS.
Nota
Em alguns ambientes Linux, como em systemd
, a extração padrão não funciona porque $HOME
não está definida. Nesses casos, é recomendável que você defina $DOTNET_BUNDLE_EXTRACT_BASE_DIR
explicitamente.
Para systemd
o , uma boa alternativa é definir DOTNET_BUNDLE_EXTRACT_BASE_DIR
no arquivo de unidade do seu serviço como %h/.net
, que systemd
se expande corretamente para $HOME/.net
a conta que executa o serviço.
[Service]
Environment="DOTNET_BUNDLE_EXTRACT_BASE_DIR=%h/.net"
Incompatibilidade de API
Algumas APIs não são compatíveis com a implantação de um único arquivo. Os aplicativos podem precisar de modificação se usarem essas APIs. Se você usar uma estrutura ou pacote de terceiros, é possível que eles usem uma dessas APIs e precisem de modificação. A causa mais comum de problemas é a dependência de caminhos de arquivo para arquivos ou DLLs fornecidos com o aplicativo.
A tabela abaixo tem os detalhes relevantes da API da biblioteca de tempo de execução para uso em um único arquivo.
API | Nota |
---|---|
Assembly.CodeBase |
Arremessos PlatformNotSupportedException. |
Assembly.EscapedCodeBase |
Arremessos PlatformNotSupportedException. |
Assembly.GetFile |
Arremessos IOException. |
Assembly.GetFiles |
Arremessos IOException. |
Assembly.Location |
Retorna uma cadeia de caracteres vazia. |
AssemblyName.CodeBase |
Devoluções null . |
AssemblyName.EscapedCodeBase |
Devoluções null . |
Module.FullyQualifiedName |
Retorna uma cadeia de caracteres com o valor de <Unknown> ou lança uma exceção. |
Marshal.GetHINSTANCE |
Devolve -1. |
Module.Name |
Retorna uma cadeia de caracteres com o valor de <Unknown> . |
Temos algumas recomendações para corrigir cenários comuns:
Para acessar arquivos ao lado do executável, use AppContext.BaseDirectory.
Para localizar o nome de arquivo do executável, use o primeiro elemento de Environment.GetCommandLineArgs(), ou começando com .NET 6, use o nome de arquivo de ProcessPath.
Para evitar o envio total de arquivos soltos, considere o uso de recursos incorporados.
Pós-processamento de binários antes da agregação
Alguns fluxos de trabalho exigem pós-processamento de binários antes da agregação. Um exemplo comum é a assinatura. O dotnet SDK fornece pontos de extensão MSBuild para permitir o processamento de binários imediatamente antes da agregação de arquivo único. As APIs disponíveis são:
- Um alvo
PrepareForBundle
que será chamado antesGenerateSingleFileBundle
- Um
<ItemGroup><FilesToBundle /></ItemGroup>
contendo todos os arquivos que serão empacotados - Uma propriedade
AppHostFile
que especificará o modelo apphost. O pós-processamento pode querer excluir o apphost do processamento.
Conectar-se a isso envolve a criação de um destino que será executado entre PrepareForBundle
e GenerateSingleFileBundle
.
Considere o seguinte exemplo de nó de projeto Target
.NET:
<Target Name="MySignedBundledFile" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle">
É possível que as ferramentas precisem copiar arquivos no processo de assinatura. Isso pode acontecer se o arquivo original for um item compartilhado que não pertence à compilação, por exemplo, o arquivo vem de um cache do NuGet. Nesse caso, espera-se que a ferramenta modifique o caminho do item correspondente FilesToBundle
para apontar para a cópia modificada.
Compactar assemblies em aplicativos de arquivo único
Aplicativos de arquivo único podem ser criados com a compactação habilitada nos assemblies incorporados. Defina a propriedade EnableCompressionInSingleFile
como true
. O único arquivo produzido terá todos os assemblies incorporados compactados, o que pode reduzir significativamente o tamanho do executável.
A compressão tem um custo de desempenho. No início do aplicativo, os assemblies devem ser descompactados na memória, o que leva algum tempo. Recomendamos que você meça a alteração de tamanho e o custo de inicialização de habilitar a compactação antes de usá-la. O impacto pode variar significativamente entre diferentes aplicações.
Inspecionar um aplicativo de arquivo único
Os aplicativos de arquivo único podem ser inspecionados usando a ferramenta ILSpy. A ferramenta pode mostrar todos os arquivos agrupados no aplicativo e pode inspecionar o conteúdo de assemblies gerenciados.