Compile la aplicación de consola .NET Core para generar un archivo EXE

452

Para un proyecto de aplicación de consola dirigido a .NET Core 1.0, no puedo averiguar cómo hacer que un .exe se genere durante la compilación. El proyecto funciona bien en depuración.

Intenté publicar el proyecto, pero tampoco funciona. Tiene sentido ya que un archivo EXE sería específico de la plataforma, pero debe haber una forma. Mis búsquedas solo han encontrado referencias a versiones anteriores de .NET Core que usaban project.json.

Siempre que construyo o publico, esto es todo lo que obtengo:

Directorio de compilación

2
  • 15
    Posible duplicado de VS2017 Compile NetCoreApp como EXEMartin Ullrich 19 de mayo de 2017 a las 16:20
  • 2
    @geekzster, recupere la eliminación: sé que no respondió la pregunta del OP, pero respondió la mía, y sospecho que muchos otros dijeron dotnet <path>.dll(¡No estaba pensando y escribiendo dotnet run <path>.dllsin éxito por razones obvias)! (Reflexionando, sería bueno si esto se cerrara a favor de la otra pregunta que tiene un conjunto similar de respuestas)Ruben Bartelink 31 oct 2018 a las 9:14
521

Para fines de depuración, puede utilizar el archivo DLL. Puedes ejecutarlo usando dotnet ConsoleApp2.dll. Si desea generar un archivo EXE, debe generar una aplicación autónoma.

Para generar una aplicación autónoma (EXE en Windows), debe especificar el tiempo de ejecución de destino (que es específico del sistema operativo al que se dirige).

Solo para versiones anteriores a.NET Core 2.0 : primero, agregue el identificador de tiempo de ejecución de los tiempos de ejecución de destino en el archivo .csproj ( lista de RID compatibles ):

<PropertyGroup>
    <RuntimeIdentifiers>win10-x64;ubuntu.16.10-x64</RuntimeIdentifiers>
</PropertyGroup>

El paso anterior ya no es necesario a partir de .NET Core 2.0 .

Luego, configure el tiempo de ejecución deseado cuando publique su aplicación:

dotnet publish -c Release -r win10-x64
dotnet publish -c Release -r ubuntu.16.10-x64
22
  • 15
    Creo que esto solo se puede hacer con la CLI. Por cierto, comenzando con .net core 2, no es necesario configurar el RuntimeIdentifieren el csproj. meziantou 14 de septiembre de 2017 a las 13:52
  • 29
    para .NET Core 2.0 ¿se puede hacer esto en Visual Studio? ¿O debo escribir estos comandos a mano? Tomasz Sikora 21/10/2017 a las 14:16
  • 82
    ¡Más de 60 MB para una aplicación de consola Hello World! shox 23 de enero de 2018 a las 5:16
  • 13
    @mikolaj Solo hay un tiempo de ejecución de destino "portátil". ¿Hay alguna forma de atraer a todos los objetivos? Estoy de acuerdo con usar la línea de comandos, sin embargo, creo que es un paso atrás. gsharp 24 de enero de 2018 a las 7:35
  • 12
    Esto no crea un ejecutable independiente. Esto crea un ejecutable, junto con una gran cantidad de otros archivos (en la carpeta de lanzamiento, me refiero). Incluyendo algunas subcarpetas con sus propios archivos. ¿Hay alguna forma de crear un verdadero ejecutable independiente ? Matthew 13 feb 2019 a las 18:50
169

ACTUALIZAR para .NET 5!

Lo siguiente se aplica a partir de NOV2020 cuando .NET 5 está oficialmente disponible.

(consulte la sección de terminología rápida a continuación, no solo los procedimientos)

Cómo hacerlo (CLI)

Prerrequisitos

  • Descargue la última versión de .net 5 SDK. Enlace

Pasos

  1. Abra una terminal (por ejemplo: bash, símbolo del sistema, powershell) y en el mismo directorio que su archivo .csproj ingrese el siguiente comando:
dotnet publish --output "{any directory}" --runtime {runtime}
  --configuration {Debug|Release} -p:PublishSingleFile={true|false}
  -p:PublishTrimmed={true|false} --self-contained {true|false}

ejemplo:

dotnet publish --output "c:/temp/myapp" --runtime win-x64 --configuration Release
  -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true

Cómo hacerlo (GUI)

Prerrequisitos

  • Si lee antes de NOV2020: última versión de Visual Studio Preview *
  • Si lee NOV2020 +: última versión de Visual Studio *

* En los 2 casos anteriores, el último SDK de .net5 se instalará automáticamente en su PC.

Pasos

  1. Haga clic con el botón derecho en Proyecto y haga clic en Publicar
    ingrese la descripción de la imagen aquí

  2. Haga clic en Inicio y elija Carpeta de destino, haga clic en siguiente y elija Carpeta Elegir destino de carpeta

  3. Ingrese cualquier ubicación de carpeta y haga clic en Finalizar

  4. Haga clic en Editar
    ingrese la descripción de la imagen aquí

  5. Elija un tiempo de ejecución de destino, marque Producir archivo único y guarde. * ingrese la descripción de la imagen aquí

  6. Haga clic en Publicar.

  7. Abra una terminal en la ubicación donde publicó su aplicación y ejecute el .exe. Ejemplo: ingrese la descripción de la imagen aquí

Un poco de terminología

Target Runtime
Consulte la lista de RID

Modo de implementación

  • Dependiente del marco significa que se generó un pequeño archivo .exe, pero la aplicación asumió que .Net 5 está instalado en la máquina host
  • Autónomo significa un archivo .exe más grande porque el .exe incluye el marco, pero luego puede ejecutar .exe en cualquier máquina, sin necesidad de que .Net 5 esté preinstalado. NOTA: CUANDO SE UTILIZA AUTÓNOMO, SE PRODUCIRÁN DEPENDENCIAS ADICIONALES (.dll), NO SOLO EL .EXE

Habilite el TLDR de compilación
ReadyToRun: es el equivalente .Net5 de Ahead of Time Compilation (AOT). Precompilada en código nativo, la aplicación generalmente se inicia más rápido. Aplicación con más rendimiento (¡o no!), Dependiendo de muchos factores. Más info aquí

Recortar ensamblajes no utilizados
Cuando se establece en verdadero, dotnet generará un .exe muy delgado y pequeño y solo incluirá lo que necesita. Tenga cuidado aquí. Ejemplo: cuando use la reflexión en su aplicación, probablemente no desee establecer esta bandera en verdadero.

Microsoft Doc


5
  • 21
    Lástima que la salida sea un montón de archivos, no solo un EXE como el antiguo .NET Framework. Tomas Karban 29/04/19 a las 15:29
  • 2
    @Tomas Karban - Fue el caso hasta que cambié el modo de implementación a "autónomo". Después de cambiar el archivo exe también apareció en la carpeta de publicación :-)Mariusz 18/06/19 a las 15:44
  • @TomasKarban .NET Core no es un tiempo de ejecución de propósito general. Está diseñado específicamente para 1) implementación en la nube / contenedor, 2) multiplataforma. También está destinado a ser temporal, es solo un truco "rápido" hasta que todo .NET pueda convertirse en código abierto. .NET 5.0 será el próximo .NET de propósito general. Luaan 12/08/19 a las 10:39
  • 3
    Aún así, es ridículo que el IDE para .NET simplemente no admita la funcionalidad más básica cuando se dirige a .NET Core. Y eso es lo que todo el mundo debe apuntar para crear aplicaciones de línea de comandos multiplataforma, por ejemplo, un compilador. Kuba hasn't forgotten Monica 18/08/19 a las 2:41
  • Esto no funcionó para mí. Probé muchas combinaciones y mi ejecutable simplemente no mostrará el contenido de mi programa, uno muy simple, Hello World. ¿Cambió algo en un año? Katherine 8/10/20 a las 21:28
19

Lo siguiente producirá, en el directorio de salida,

  • todas las referencias del paquete
  • el ensamblaje de salida
  • el exe de bootstrapping

Pero no contiene todos los ensamblados en tiempo de ejecución de .NET Core.

<PropertyGroup>
  <Temp>$(SolutionDir)\packaging\</Temp>
</PropertyGroup>

<ItemGroup>
  <BootStrapFiles Include="$(Temp)hostpolicy.dll;$(Temp)$(ProjectName).exe;$(Temp)hostfxr.dll;"/>
</ItemGroup>

<Target Name="GenerateNetcoreExe"
        AfterTargets="Build"
        Condition="'$(IsNestedBuild)' != 'true'">
  <RemoveDir Directories="$(Temp)" />
  <Exec
    ConsoleToMSBuild="true"
    Command="dotnet build $(ProjectPath) -r win-x64 /p:CopyLocalLockFileAssemblies=false;IsNestedBuild=true --output $(Temp)" >
    <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
  </Exec>
  <Copy
    SourceFiles="@(BootStrapFiles)"
    DestinationFolder="$(OutputPath)"
  />

</Target>

Lo envolví en una muestra aquí: https://github.com/SimonCropp/NetCoreConsole

2
  • 1
    excepto que ($ Temp) apunta a mi c: \ Users \ xxx \ AppData \ Local \ Temp que obviamente no se puede eliminar / limpiar, ni es recomendable hacerloAdaptabi 9/07/19 a las 12:13
  • 1
    @Adaptabi Temp se define como una propiedad al comienzo del scriptSimon 18/07/19 a las 1:01
4

Si un archivo .bat es aceptable, puede crear un archivo bat con el mismo nombre que el archivo DLL (y colocarlo en la misma carpeta), luego pegar el siguiente contenido:

dotnet %~n0.dll %*

Obviamente, esto supone que la máquina tiene .NET Core instalado y disponible globalmente.

c:\> "path\to\batch\file" -args blah

(Esta respuesta se deriva del comentario de Chet ).

0

Aquí está mi solución hacky: genere una aplicación de consola (.NET Framework) que lea su propio nombre y argumentos, y luego llame dotnet [nameOfExe].dll [args].

Por supuesto, esto supone que .NET está instalado en la máquina de destino.

Aquí está el código. ¡Siéntete libre de copiar!

using System;
using System.Diagnostics;
using System.Text;

namespace dotNetLauncher
{
    class Program
    {
        /*
            If you make .NET Core applications, they have to be launched like .NET blah.dll args here
            This is a convenience EXE file that launches .NET Core applications via name.exe
            Just rename the output exe to the name of the .NET Core DLL file you wish to launch
        */
        static void Main(string[] args)
        {
            var exePath = AppDomain.CurrentDomain.BaseDirectory;
            var exeName = AppDomain.CurrentDomain.FriendlyName;
            var assemblyName = exeName.Substring(0, exeName.Length - 4);
            StringBuilder passInArgs = new StringBuilder();
            foreach(var arg in args)
            {
                bool needsSurroundingQuotes = false;
                if (arg.Contains(" ") || arg.Contains("\""))
                {
                    passInArgs.Append("\"");
                    needsSurroundingQuotes = true;
                }
                passInArgs.Append(arg.Replace("\"","\"\""));
                if (needsSurroundingQuotes)
                {
                    passInArgs.Append("\"");
                }

                passInArgs.Append(" ");
            }
            string callingArgs = $"\"{exePath}{assemblyName}.dll\" {passInArgs.ToString().Trim()}";

            var p = new Process
            {
                StartInfo = new ProcessStartInfo("dotnet", callingArgs)
                {
                    UseShellExecute = false
                }
            };

            p.Start();
            p.WaitForExit();
        }
    }
}
1
  • 7
    Si va a tener un archivo adicional de todos modos, ¿por qué no crear un archivo bat que contengadotnet [nameOfExe].dll %*Chet 27 feb 2019 a las 0:36