Publicación self-contained y single-file en .NET Core - Code Variables -->
Code Variables Code Variables

Latest news

جاري التحميل ...

Publicación self-contained y single-file en .NET Core

.NET CoreComo sabemos, para ejecutar cualquier tipo de aplicación .NET Core en un equipo necesitamos tener instalado el runtime o el SDK de la plataforma. Esto es algo que podemos hacer muy fácilmente, simplemente acudiendo a la página oficial de descargas, eligiendo nuestro sistema operativo y siguiendo las instrucciones de instalación.

El hecho de que en el equipo destino esté preinstalado el runtime es muy interesante, entre otras cosas porque permite asegurar de antemano que en él se encontrarán todas las dependencias (frameworks, bibliotecas, paquetes, metapaquetes) necesarios para una correcta ejecución. Por tanto, para distribuir nuestra aplicación sólo debemos generar lo relativo a nuestro código, el resto ya estará allí.
Esta forma de publicar aplicaciones se denomina framework-dependent, pues dependen de que determinados componentes del framework estén instalado en el destino.
Por ejemplo, el paquete de publicación de una aplicación de consola prácticamente vacía, que únicamente muestra el mensaje "Hello world!", ocuparía solo 175K:
D:\MyConsoleApp\output>dir

El volumen de la unidad D es Datos
El número de serie del volumen es: 8CBC-81E3

Directorio de D:\MyConsoleApp\output

09/02/2020 18:47 <DIR> .
09/02/2020 18:47 <DIR> ..
09/02/2020 18:46 428 MyConsoleApp.deps.json
09/02/2020 18:46 4.608 MyConsoleApp.dll
09/02/2020 18:46 169.984 MyConsoleApp.exe
09/02/2020 18:46 668 MyConsoleApp.pdb
09/02/2020 18:46 154 MyConsoleApp.runtimeconfig.json
5 archivos 175.842 bytes
2 dirs 463.058.874.368 bytes libres

D:\MyConsoleApp\output>_
Otra ventaja de este tipo de distribución es que es cross platform pura, es decir, podemos copiar los archivos a cualquiera de los sistemas operativos soportados y, siempre que dispongan del runtime, nuestra aplicación podrá correr sobre ellos sin problema.

Y todo esto está muy bien, pero, ¿qué pasa si quiero crear una aplicación portable, de forma que pueda distribuirla y ejecutarla sin necesidad de que el equipo destino tenga nada preinstalado?

Pues eso es lo que veremos en este post ;)

Publicación self-contained

Este tipo de publicación incluye todo lo necesario para que la aplicación funcione, sin necesidad de que el equipo destino disponga de componentes preinstalados. Es la opción más segura si desconocemos qué runtimes están instalados en el servidor, o incluso si queremos aislarnos de cambios o actualizaciones que pudieran instalarse en el servidor y que, de alguna forma, pudieran salpicarnos en el futuro.

Para publicar en modo self contained desde Visual Studio, sólo tendremos que acudir al perfil de publicación y editar sus settings de la siguiente forma:

Perfil de publicación estableciendo el deployment mode a self-contained y el target runtime a win-x64

Como se observa en la captura anterior, en el Deployment mode debemos seleccionar "Self-contained", mientras que en la opción Target Runtime tendremos que indicar el runtime sobre el que vamos a ejecutar la aplicación. Este paso es importante, pues hará que los binarios a incluir en el paquete distribuible sean los específicos para el entorno indicado.

Esto también podemos hacerlo si queremos generar el paquete de publicación desde la línea de comandos, por ejemplo como sigue:
D:\MyConsoleApp>dotnet publish --self-contained -r win-x64 -c release -o output

Microsoft (R) Build Engine versión 16.4.0+e901037fe para .NET Core
Copyright (C) Microsoft Corporation. Todos los derechos reservados.

Restauración realizada en 138,79 ms para D:\MyConsoleApp\MyConsoleApp.csproj.
MyConsoleApp -> D:\MyConsoleApp\bin\release\netcoreapp3.1\win-x64\MyConsoleApp.dll
MyConsoleApp -> D:\MyConsoleApp\output\

D:\MyConsoleApp\output>_
En cualquier caso, el principal inconveniente de este modelo de distribución es que los archivos a mover son bastantes más, por lo que los despliegues serán más lentos y ocuparán mucho más espacio en disco. Por ejemplo, si hacemos un dir en la carpeta de resultados de la publicación veremos que hemos pasado de tener cinco archivos a más de doscientos, y el tamaño de menos de 200Kb a 69Mb:
D:\MyConsoleApp\output>dir

El volumen de la unidad D es Datos
El número de serie del volumen es: 8CBC-81E3

Directorio de D:\MyConsoleApp\output

09/02/2020 18:56 <DIR> .
09/02/2020 18:56 <DIR> ..
20/04/2018 06:28 19.208 api-ms-win-core-console-l1-1-0.dll
20/04/2018 06:28 18.696 api-ms-win-core-datetime-l1-1-0.dll
20/04/2018 06:28 18.696 api-ms-win-core-debug-l1-1-0.dll
20/04/2018 06:28 18.696 api-ms-win-core-errorhandling-l1-1-0.dll
20/04/2018 06:29 22.280 api-ms-win-core-file-l1-1-0.dll
20/04/2018 06:37 18.696 api-ms-win-core-file-l1-2-0.dll
(... Omitidos más de 200 archivos ...)
09/12/2019 03:39 14.928 System.Xml.XmlDocument.dll
09/12/2019 03:40 16.768 System.Xml.XmlSerializer.dll
09/12/2019 03:40 14.200 System.Xml.XPath.dll
09/12/2019 03:39 15.952 System.Xml.XPath.XDocument.dll
20/04/2018 06:37 1.016.584 ucrtbase.dll
09/12/2019 03:40 15.440 WindowsBase.dll
225 archivos 69.122.606 bytes
2 dirs 462.918.475.776 bytes libres

D:\MyConsoleApp\output>_
Sí, pensaréis que es un exceso para mostrar un simple "Hola mundo", pero si tenemos en cuenta que estos archivos incluyen el framework y todas sus bibliotecas no sale tan mal parada la cosa. Lo importante en este caso es que podemos copiar esta carpeta a cualquier servidor Windows x64 y funcionará correctamente, sin necesidad de tener nada preinstalado.

Pero aún podemos mejorarlo un poco...

Eliminando peso: Trimming de paquetes

Cuando hemos echado un ojo al contenido de la carpeta de destino de la publicación, vimos archivos como System.Xml.XmlSerializer.dll o System.Xml.XPath.dll... ¿realmente necesitamos desplegar estos ensamblados en nuestra aplicación, que sólo muestra un "Hello world!"? Seguro que no.

Desde .NET Core 3.0, el SDK incluye de serie una funcionalidad que permite eliminar de los archivos distribuibles los paquetes que no sean utilizados por nuestra aplicación o sus dependencias. Para activarlo, basta con añadir el elemento <PublishTrimmed> en el archivo .csproj del proyecto:
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
Hecho esto, si volvemos a repetir la operación de publicación, veremos que el paquete de publicación se reducirá bastante:
D:\MyConsoleApp>dotnet publish --self-contained -r win-x64 -c release -o output

Microsoft (R) Build Engine versión 16.4.0+e901037fe para .NET Core
Copyright (C) Microsoft Corporation. Todos los derechos reservados.

Restauración realizada en 26,72 ms para D:\MyConsoleApp\MyConsoleApp.csproj.
MyConsoleApp -> D:\MyConsoleApp\bin\Release\netcoreapp3.1\win-x64\MyConsoleApp.dll
Se está optimizando el tamaño de los ensamblados, lo que puede cambiar el
comportamiento de la aplicación. Asegúrese de probarlo después de publicar.
Consulte https://aka.ms/dotnet-illink
MyConsoleApp -> D:\MyConsoleApp\output\

D:\MyConsoleApp>dir output

El volumen de la unidad D es Datos
El número de serie del volumen es: 8CBC-81E3

Directorio de D:\MyConsoleApp\output
09/02/2020 19:05 <DIR> .
09/02/2020 19:05 <DIR> ..
20/04/2018 06:28 19.208 api-ms-win-core-console-l1-1-0.dll
20/04/2018 06:28 18.696 api-ms-win-core-datetime-l1-1-0.dll
20/04/2018 06:28 18.696 api-ms-win-core-debug-l1-1-0.dll
20/04/2018 06:28 18.696 api-ms-win-core-errorhandling-l1-1-0.dll
(... Omitidos más de 50 archivos ...)
09/02/2020 19:05 62.464 System.Console.dll
07/12/2019 16:40 9.555.840 System.Private.CoreLib.dll
09/02/2020 19:05 74.752 System.Runtime.Extensions.dll
20/04/2018 06:37 1.016.584 ucrtbase.dll
63 archivos 26.499.046 bytes
2 dirs 462.951.739.392 bytes libres

D:\MyConsoleApp>_
Mucho mejor ahora: hemos pasado de 225 archivos a 63, y reducido el peso de 69 a 26Mb. Aunque sigue siendo demasiado para un simple "Hello world!", al menos sabemos que es el mínimo al que podemos aspirar si queremos que el paquete distribuible de nuestra aplicación incluya el framework sobre el que será ejecutada.

Un último detalle: como hemos comentado anteriormente, el trimming eliminará los paquetes que detecte que no son utilizados, pero puede haber ocasiones en las que nos interesa que este mecanismo no elimine algún ensamblado en particular. Por ejemplo, si nuestra aplicación utiliza reflexión o cualquier otro mecanismo para cargar o utilizar ensamblados, el trimmer no los detectará y asumirá que no se están usando, lo que provocará errores en tiempo de ejecución.

Para indicar que un ensamblado debe ser incluido obligatoriamente en el paquete de publicación, podemos usar el elemento <TrimmerRootAssembly> en el .csproj:
<ItemGroup>
<TrimmerRootAssembly Include="System.Xml.XmlSerializer.dll" />
</ItemGroup>

Publicación single-file: ¡un único ejecutable!

A partir de .NET Core 3, tenemos disponible un nuevo modelo de distribución que permite incluir en un único ejecutable todo lo necesario para que nuestra aplicación funcione sin tener nada preinstalado.

Podemos publicar como archivo único mediante una orden de la CLI como la siguiente:
D:\MyConsoleApp>dotnet publish -r win10-x64 -p:PublishSingleFile=true -o output

Microsoft (R) Build Engine versión 16.4.0+e901037fe para .NET Core
Copyright (C) Microsoft Corporation. Todos los derechos reservados.

Restauración realizada en 124,52 ms para D:\MyConsoleApp\MyConsoleApp.csproj.
MyConsoleApp -> D:\MyConsoleApp\bin\Debug\netcoreapp3.1\win10-x64\MyConsoleApp.dll
Se está optimizando el tamaño de los ensamblados, lo que puede cambiar el
comportamiento de la aplicación. Asegúrese de probarlo después de publicar.
Consulte https://aka.ms/dotnet-illink
MyConsoleApp -> D:\MyConsoleApp\output\

D:\MyConsoleApp>dir output

El volumen de la unidad D es Datos
El número de serie del volumen es: 8CBC-81E3

Directorio de D:\MyConsoleApp\output

09/02/2020 19:10 <DIR> .
09/02/2020 19:10 <DIR> ..
09/02/2020 19:10 26.501.267 MyConsoleApp.exe
09/02/2020 19:10 680 MyConsoleApp.pdb
2 archivos 26.501.947 bytes
2 dirs 462.872.199.168 bytes libres

D:\MyConsoleApp>_
En lugar de tener que indicar tantos parámetros cada vez, también podríamos conseguirlo modificando el archivo .csproj. Para ello, bastaría con establecer a true el elemento <PublishSingleFile>, aunque al hacerlo, además, será obligatorio introducir el runtime de destino en el item <RuntimeIdentifier>. El resultado final podría ser algo así (trimming incluido):
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
En cualquier caso, fijaos que podríamos distribuir la aplicación, el runtime y el framework en un único ejecutable de 26Mb (usando el trimmer).

Publicado en Variable not found.

Comments



If you like the content of our blog, we hope to stay in constant communication, just enter your email to subscribe to the blog's express mail to receive new blog updates, and you can send a message by clicking on the button next ...

إتصل بنا

About the site

author Code Variables  Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET Core, MVC, Blazor, SignalR, Entity Framework, C#, Azure, Javascript...

Learn more ←

Blog visitors

Blog stats

All Copyrights Reserved

Code Variables

2019