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

414

Para un proyecto de aplicación de consola dirigido a .NET Core 1.0, no puedo entender cómo obtener un .exe para generar durante la compilación. El proyecto funciona bien en depuración.

He intentado publicar el proyecto, pero eso tampoco funciona. Tiene sentido ya que un archivo EXE sería específico de la plataforma, pero debe haber una manera. Mis búsquedas solo han hecho referencia a versiones anteriores de .NET Core que usaban project.json.

Cada vez que construyo o publico, esto es todo lo que obtengo:

Construir directorio

kenchilada
fuente
15
Posible duplicado de VS2017 Compile NetCoreApp como EXE
Martin Ullrich
2
@geekzster, por favor, recupere: ¡sé que no respondió la pregunta de OP, pero respondió la mía, y sospecho que la de muchos otros al decir 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

Respuestas:

480

Para fines de depuración, puede usar 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 antes de .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
meziantou
fuente
15
Creo que esto solo se puede hacer con la CLI. Por cierto, comenzando con .net core 2, no es necesario configurarlo RuntimeIdentifieren csproj.
meziantou
26
para .NET Core 2.0, ¿se puede hacer esto en Visual Studio? ¿O debo escribir estos comandos a mano?
Tomasz Sikora
77
¡Más de 60 MB para una aplicación de consola Hello World!
shox
13
@mikolaj Solo hay un tiempo de ejecución objetivo "portátil". ¿Hay alguna manera de atraer a todos los objetivos? Estoy de acuerdo con usar la línea de comando, sin embargo, creo que es un paso atrás.
gsharp
10
Esto no crea un ejecutable independiente. Esto crea un ejecutable, junto con una gran cantidad de otros archivos (en la carpeta de lanzamiento, quiero decir). Incluyendo algunas subcarpetas con sus propios archivos. ¿Hay alguna manera de crear un verdadero ejecutable independiente ?
Mateo
122

ACTUALIZACIÓN (31-OCT-2019)

Para cualquiera que quiera hacer esto a través de una GUI y:

  • Está usando Visual Studio 2019
  • Tiene instalado .NET Core 3.0 (incluido en la última versión de Visual Studio 2019)
  • Quiere generar un solo archivo

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Nota

Observe el tamaño de archivo grande para una aplicación tan pequeña

Ingrese la descripción de la imagen aquí

Puede agregar la propiedad "PublishTrimmed". La aplicación solo incluirá componentes utilizados por la aplicación. Precaución : no hagas esto si estás usando la reflexión

Ingrese la descripción de la imagen aquí

Publicar de nuevo

Ingrese la descripción de la imagen aquí


Publicación anterior

Para cualquiera que use Visual Studio y quiera hacer esto a través de la GUI, consulte los pasos a continuación:

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí

Francisco Vilches
fuente
19
Lástima que la salida es un montón de archivos, no solo un EXE como el antiguo .NET Framework.
Tomas Karban
2
@Tomas Karban - Fue el caso hasta que cambié el modo de implementación a "autónomo" Después de que el archivo exe de cambio apareciera en la carpeta de publicación también :-)
Mariusz
@TomasKarban .NET Core no es un tiempo de ejecución de propósito general. Está específicamente diseñado para 1) despliegue de 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
3
Aún así, es ridículo que IDE para .NET simplemente no admita la funcionalidad más básica cuando se dirige a .NET Core. Y eso es a lo que todos deben apuntar para crear aplicaciones de línea de comandos multiplataforma, por ejemplo, un compilador.
Vuelva a instalar Mónica
18

Lo siguiente producirá, en el directorio de salida,

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

Pero no contiene todos los ensamblados de 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

Simón
fuente
excepto que ($ Temp) apunta a mi c: \ Users \ xxx \ AppData \ Local \ Temp que obviamente no se puede eliminar / limpiar, ni es aconsejable hacerlo
Adaptabi
1
@Adaptabi Temp se define como una propiedad al comienzo del script
Simon
2

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 pegue el siguiente contenido:

dotnet %~n0.dll %*

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

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

(Esta respuesta se deriva del comentario de Chet ).

Ambrose Leung
fuente
0

Aquí está mi solución alternativa: generar 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éntase 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();
        }
    }
}
Ambrose Leung
fuente
66
Si de todos modos va a tener un archivo adicional, ¿por qué no crear un archivo bat que contengadotnet [nameOfExe].dll %*
Chet