Implementación de un archivo único

La agrupación de todos los archivos dependientes de la aplicación en un único binario proporciona a un desarrollador de aplicaciones la opción atractiva de implementar y distribuir la aplicación como un único archivo. La implementación de archivo único está disponible para el modelo de implementación dependiente del marco y para aplicaciones independientes.

El tamaño del archivo único de una aplicación independiente es grande, ya que incluye el runtime y las bibliotecas del marco. En .NET 6, puede publicar recortado para reducir el tamaño total de las aplicaciones compatibles con el recorte. La opción de implementación de archivo único se puede combinar con las opciones de publicación ReadyToRun y Trim.

Importante

Para ejecutar una sola aplicación de archivo en Windows 7, debe usar .NET Runtime 6.0.3 o posterior.

Archivo del proyecto de ejemplo

Este es un archivo del proyecto de ejemplo, que especifica la publicación de un archivo ú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 propiedades tienen las siguientes funciones:

  • PublishSingleFile. Habilita la publicación de un archivo único. También habilita las advertencias de archivo único durante dotnet build.
  • SelfContained. Determina si la aplicación es independiente o dependiente del marco.
  • RuntimeIdentifier. Especifica el SO y el tipo de CPU que tiene como destino. También establece <SelfContained>true</SelfContained> de forma predeterminada.

Las aplicaciones de archivo único siempre son específicas del SO y de la arquitectura. Debe publicar para cada configuración, como Linux x64, Linux Arm64, Windows x64, etc.

Los archivos de configuración del runtime, como *.runtimeconfig.json y *.deps.json, se incluyen en el archivo único. Si se necesita un archivo de configuración adicional, puede colocarlo junto al archivo único.

Publicación de una aplicación de archivo único

Publique una aplicación de archivo único mediante el comando dotnet publish.

  1. Agregue <PublishSingleFile>true</PublishSingleFile> al archivo del proyecto.

    Este cambio generará una aplicación de archivo único en la publicación independiente. También muestra advertencias de compatibilidad de archivo único durante la compilación.

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>
    
  2. Publique la aplicación para un identificador de runtime específico mediante dotnet publish -r <RID>

    En el ejemplo siguiente se publica la aplicación para Windows como aplicación independiente de archivo único.

    dotnet publish -r win-x64

    En el ejemplo siguiente se publica la aplicación para Linux como una aplicación de archivo único dependiente del marco.

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

<PublishSingleFile> se debe establecer en el archivo del proyecto para habilitar el análisis de archivos durante la compilación, pero también es posible pasar estas opciones como argumentos de dotnet publish:

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

Para obtener más información, vea Publicación de aplicaciones de .NET Core con la CLI de .NET.

Exclusión de archivos de la inserción

Algunos archivos se pueden excluir de forma explícita de su inserción en el único archivo si se establecen los metadatos siguientes:

<ExcludeFromSingleFile>true</ExcludeFromSingleFile>

Por ejemplo, para colocar algunos archivos en el directorio de publicación pero sin agruparlos en el archivo:

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

Inclusión de archivos PDB dentro de la agrupación

El archivo PDB de un ensamblado se puede insertar en el propio ensamblado (.dll) mediante la configuración siguiente. Puesto que los símbolos forman parte del ensamblado, también forman parte de la aplicación:

<DebugType>embedded</DebugType>

Por ejemplo, agregue la siguiente propiedad al archivo de proyecto de un ensamblado para insertar el archivo PDB en ese ensamblado:

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

Otras consideraciones

Las aplicaciones de archivo único tienen todos los archivos PDB relacionados junto con la aplicación, no agrupados de forma predeterminada. Si desea incluir archivos PDB dentro del ensamblado para los proyectos que quiera compilar, establezca DebugType en embedded. Consulte Inclusión de archivos PDB dentro de la agrupación.

Los componentes de C++ administrados no son adecuados para la implementación de archivos únicos. Se recomienda escribir aplicaciones en C# u otro lenguaje de C++ no administrado para que sean compatibles con un archivo único.

Bibliotecas nativas

Solo los archivos DLL administrados se agrupan con la aplicación en un único archivo ejecutable. Cuando se inicia la aplicación, los archivos DLL administrados se extraen y se cargan en memoria, lo que evita la extracción en una carpeta. Gracias a este enfoque, los archivos binarios administrados se insertan en la agrupación de archivo único, pero los archivos binarios nativos del propio runtime principal son archivos independientes.

A fin de insertar esos archivos para la extracción y obtener un archivo de salida, establezca la propiedad IncludeNativeLibrariesForSelfExtract en true.

Si se especifica IncludeAllContentForSelfExtract, se extraen todos los archivos, incluidos los ensamblados administrados, antes de ejecutar el archivo ejecutable. Esto puede resultar útil para problemas de compatibilidad de aplicaciones poco frecuentes.

Importante

Si se usa la extracción, los archivos se extraen en el disco antes de que se inicie la aplicación:

  • Si la variable de entorno DOTNET_BUNDLE_EXTRACT_BASE_DIR se establece en una ruta de acceso, los archivos se extraerán en un directorio de esa ruta de acceso.
  • De lo contrario, si se ejecuta en Linux o macOS, los archivos se extraerán en un directorio de $HOME/.net.
  • Si se ejecuta en Windows, los archivos se extraerán en un directorio de %TEMP%/.net.

Para evitar alteraciones, los usuarios o servicios con privilegios diferentes no deben poder escribir en estos directorios. No use /tmp o /var/tmp en la mayoría de los sistemas Linux y macOS.

Nota

En algunos entornos de Linux, como systemd, la extracción predeterminada no funciona porque $HOME no se ha definido. En estos casos, se recomienda establecer $DOTNET_BUNDLE_EXTRACT_BASE_DIR de forma explícita.

En el caso de systemd, una buena alternativa es definir DOTNET_BUNDLE_EXTRACT_BASE_DIR en el archivo unitario del servicio como %h/.net, que systemd amplía correctamente a $HOME/.net para la cuenta que ejecuta el servicio.

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

Incompatibilidad de API

Algunas API no son compatibles con la implementación de un archivo único. Las aplicaciones pueden requerir modificaciones si usan estas API. Si usa un paquete o un marco de terceros, es posible que estos puedan usar alguna de las API que necesitan modificación. La causa más común de los problemas es la dependencia de las rutas de acceso de archivo de los archivos o DLL que se incluyen con la aplicación.

En la tabla siguiente se incluyen los detalles pertinentes de la API de la biblioteca del runtime para el uso de un archivo único.

API Nota:
Assembly.CodeBase Produce PlatformNotSupportedException.
Assembly.EscapedCodeBase Produce PlatformNotSupportedException.
Assembly.GetFile Produce IOException.
Assembly.GetFiles Produce IOException.
Assembly.Location Devuelve una cadena vacía.
AssemblyName.CodeBase Devuelve null.
AssemblyName.EscapedCodeBase Devuelve null.
Module.FullyQualifiedName Devuelve una cadena con el valor de <Unknown> o produce una excepción.
Marshal.GetHINSTANCE Devuelve -1.
Module.Name Devuelve una cadena con el valor de <Unknown>.

Tenemos algunas recomendaciones para solucionar escenarios comunes:

Archivos binarios de procesamiento posterior antes de la agrupación

Algunos flujos de trabajo requieren procesamiento posterior de archivos binarios antes de la agrupación. Un ejemplo común es la firma. El SDK de dotnet proporciona puntos de extensión de MSBuild para permitir el procesamiento de archivos binarios justo antes de que se realice la agrupación de archivos únicos. Las API disponibles son las siguientes:

  • Un elemento PrepareForBundle de destino al que se llamará antes de GenerateSingleFileBundle.
  • Un elemento <ItemGroup><FilesToBundle /></ItemGroup> que contiene todos los archivos que se agruparán.
  • Una propiedad AppHostFile que especificará la plantilla de apphost. Es posible que el procesamiento posterior quiera excluir el apphost del procesamiento.

Conectar esto implica la creación de un destino que se ejecutará entre PrepareForBundle y GenerateSingleFileBundle.

Considere el siguiente ejemplo de nodo Target de proyecto de .NET:

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

Es posible que las herramientas necesiten copiar archivos en el proceso de firma. Esto podría ocurrir si el archivo original es un elemento compartido que no pertenece a la compilación como, por ejemplo, que el archivo proceda de una caché de NuGet. En tal caso, se espera que la herramienta modifique la ruta de acceso del elemento FilesToBundle correspondiente para que apunte a la copia modificada.

Comprimir ensamblados en aplicaciones de archivo único

Se pueden crear aplicaciones de archivo único con la compresión habilitada en los ensamblados insertados. Establezca la propiedad EnableCompressionInSingleFile en true. El archivo único generado tendrá comprimidos todos los ensamblados insertados, lo que puede reducir significativamente el tamaño del archivo ejecutable.

La compresión conlleva un costo de rendimiento. Al iniciar la aplicación, los ensamblados se deben descomprimir en memoria, lo que tarda algún tiempo. Se recomienda medir tanto el cambio de tamaño como el coste inicial de la habilitación de la compresión antes de ponerla en práctica. El impacto puede variar significativamente según la aplicación.

Inspección de una aplicación de archivo único

Las aplicaciones de archivo único se pueden inspeccionar mediante la herramienta ILSpy. La herramienta puede mostrar todos los archivos agrupados en la aplicación e inspeccionar el contenido de los ensamblados administrados.

Vea también