Créer une application console .NET Core pour générer un EXE

414

Pour un projet d'application console ciblant .NET Core 1.0, je ne peux pas comprendre comment obtenir un fichier .exe à afficher lors de la génération. Le projet fonctionne bien en débogage.

J'ai essayé de publier le projet, mais cela ne fonctionne pas non plus. Cela a du sens car un fichier EXE serait spécifique à la plate-forme, mais il doit y avoir un moyen. Mes recherches ont uniquement révélé des références à des versions plus anciennes de .NET Core qui utilisaient project.json.

Chaque fois que je crée ou publie, c'est tout ce que je reçois:

Créer un répertoire

kenchilada
la source
15
Copie
Martin Ullrich
2
@geekzster s'il vous plaît annuler la suppression - Je sais que vous n'avez pas répondu à la question OP, mais vous avez répondu à la mienne, et je soupçonne cela de beaucoup d'autres en disant dotnet <path>.dll(je ne pensais pas et je tapais dotnet run <path>.dllsans succès pour des raisons évidentes)! (À la réflexion, il serait bon que cela soit clos en faveur de l'autre question qui a un ensemble de réponses similaire)
Ruben Bartelink

Réponses:

480

À des fins de débogage, vous pouvez utiliser le fichier DLL. Vous pouvez l'exécuter en utilisant dotnet ConsoleApp2.dll. Si vous souhaitez générer un fichier EXE, vous devez générer une application autonome.

Pour générer une application autonome (EXE sous Windows), vous devez spécifier le runtime cible (qui est spécifique au système d'exploitation que vous ciblez).

Pre-.NET Core 2.0 uniquement : ajoutez d'abord l'identifiant d'exécution des runtimes cibles dans le fichier .csproj ( liste des RID pris en charge ):

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

L'étape ci-dessus n'est plus requise à partir de .NET Core 2.0 .

Ensuite, définissez le runtime souhaité lorsque vous publiez votre application:

dotnet publish -c Release -r win10-x64
dotnet publish -c Release -r ubuntu.16.10-x64
meziantou
la source
15
Je pense que cela ne peut être fait qu'avec la CLI. BTW, à partir de .net core 2, vous n'avez pas besoin de définir le RuntimeIdentifierdans le csproj.
meziantou
26
pour .NET Core 2.0, cela peut-il être fait dans Visual Studio? Ou je dois taper ces commandes à la main?
Tomasz Sikora
77
Plus de 60 Mo pour une application console Hello world!
shox
13
@mikolaj Il n'y a qu'un seul runtime cible "portable". Existe-t-il un moyen de faire entrer toutes les cibles? Je suis d'accord pour utiliser la ligne de commande, mais pensez que c'est un pas en arrière.
gsharp
10
Cela ne crée pas d'exécutable autonome. Cela crée un exécutable, avec une foule d'autres fichiers (dans le dossier de publication, je veux dire). Y compris certains sous-dossiers avec leurs propres fichiers. Existe-t-il un moyen de créer un véritable exécutable autonome ?
Matthew
122

MISE À JOUR (31-OCT-2019)

Pour tous ceux qui souhaitent le faire via une interface graphique et:

  • Utilise Visual Studio 2019
  • A .NET Core 3.0 installé (inclus dans la dernière version de Visual Studio 2019)
  • Veut générer un seul fichier

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

entrez la description de l'image ici

Entrez la description de l'image ici

Remarque

Remarquez la grande taille du fichier pour une si petite application

Entrez la description de l'image ici

Vous pouvez ajouter la propriété "PublishTrimmed". L'application inclura uniquement les composants utilisés par l'application. Attention : ne faites pas cela si vous utilisez la réflexion

Entrez la description de l'image ici

Publier à nouveau

Entrez la description de l'image ici


Post précédent

Pour toute personne qui utilise Visual Studio et souhaite le faire via l'interface graphique, consultez les étapes ci-dessous:

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Entrez la description de l'image ici

Francisco Vilches
la source
19
Dommage que la sortie soit un tas de fichiers, pas seulement un EXE comme l'ancien .NET Framework.
Tomas Karban
2
@Tomas Karban - C'était le cas jusqu'à ce que je change le mode de déploiement en "autonome". Après le changement, le fichier exe est également apparu dans le dossier de publication :-)
Mariusz
@TomasKarban .NET Core n'est pas un runtime à usage général. Il est spécialement conçu pour 1) le déploiement cloud / conteneur, 2) multi-plateforme. Il est également censé être temporaire - c'est juste un hack "rapide" jusqu'à ce que tout .NET puisse devenir open source. .NET 5.0 va être le prochain .NET à usage général.
Luaan
3
Pourtant, il est ridicule que l'IDE pour .NET ne prenne tout simplement pas en charge les fonctionnalités les plus élémentaires lorsque vous ciblez .NET Core. Et c'est ce que tout le monde doit cibler pour créer des applications en ligne de commande multiplateforme - disons, un compilateur.
Rétablir Monica
18

Ce qui suit produira, dans le répertoire de sortie,

  • toutes les références du package
  • l'ensemble de sortie
  • l'exe bootstrapping

Mais il ne contient pas tous les assemblys d'exécution .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>

Je l'ai enveloppé dans un échantillon ici: https://github.com/SimonCropp/NetCoreConsole

Simon
la source
sauf que ($ Temp) pointe vers mon c: \ Users \ xxx \ AppData \ Local \ Temp qui ne peut évidemment pas être supprimé / nettoyé - ni il est conseillé de le faire
Adaptabi
1
@Adaptabi Temp est défini comme une propriété au début du script
Simon
2

Si un fichier .bat est acceptable, vous pouvez créer un fichier bat avec le même nom que le fichier DLL (et le placer dans le même dossier), puis collez le contenu suivant:

dotnet %~n0.dll %*

Évidemment, cela suppose que .NET Core est installé et disponible dans le monde entier sur la machine.

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

(Cette réponse est dérivée du commentaire de Chet .)

Ambrose Leung
la source
0

Voici ma solution de contournement hacky - générer une application console (.NET Framework) qui lit son propre nom et arguments, puis appelle dotnet [nameOfExe].dll [args].

Bien sûr, cela suppose que .NET est installé sur la machine cible.

Voici le code. N'hésitez pas à copier!

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
la source
6
Si vous avez quand même un fichier supplémentaire, pourquoi ne pas simplement créer un fichier bat contenantdotnet [nameOfExe].dll %*
Chet