Erstellen Sie eine .NET Core-Konsolenanwendung, um eine EXE-Datei auszugeben

412

Bei einem Konsolenanwendungsprojekt, das auf .NET Core 1.0 abzielt, kann ich nicht herausfinden, wie eine EXE-Datei während der Erstellung ausgegeben wird. Das Projekt läuft gut im Debug.

Ich habe versucht, das Projekt zu veröffentlichen, aber das funktioniert auch nicht. Es ist sinnvoll, da eine EXE-Datei plattformspezifisch wäre, aber es muss einen Weg geben. Meine Suche ergab nur Verweise auf ältere .NET Core-Versionen, die project.json verwendeten.

Wann immer ich baue oder veröffentliche, ist dies alles, was ich bekomme:

Verzeichnis erstellen

kenchilada
quelle
15
Mögliches Duplikat von VS2017 Compile NetCoreApp als EXE
Martin Ullrich
2
@geekzster bitte rückgängig machen - Ich weiß, dass Sie die OP-Frage nicht beantwortet haben, aber Sie haben meine beantwortet, und ich vermute das von vielen anderen, indem dotnet <path>.dllich sagte (ich habe dotnet run <path>.dllaus offensichtlichen Gründen nicht ohne Erfolg gedacht und getippt )! (Nachdenklich wäre es gut, wenn dies zugunsten der anderen Frage geschlossen würde, die ähnliche Antworten hat)
Ruben Bartelink

Antworten:

480

Zum Debuggen können Sie die DLL-Datei verwenden. Sie können es mit ausführen dotnet ConsoleApp2.dll. Wenn Sie eine EXE-Datei generieren möchten, müssen Sie eine eigenständige Anwendung generieren.

Um eine eigenständige Anwendung (EXE in Windows) zu generieren, müssen Sie die Ziellaufzeit angeben (die für das Betriebssystem, auf das Sie abzielen, spezifisch ist).

Nur Pre-.NET Core 2.0 : Fügen Sie zunächst die Laufzeitkennung der Ziellaufzeiten in die .csproj-Datei ein ( Liste der unterstützten RIDs ):

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

Der obige Schritt ist ab .NET Core 2.0 nicht mehr erforderlich .

Stellen Sie dann die gewünschte Laufzeit ein, wenn Sie Ihre Anwendung veröffentlichen:

dotnet publish -c Release -r win10-x64
dotnet publish -c Release -r ubuntu.16.10-x64
Meziantou
quelle
15
Ich denke, das kann nur mit der CLI gemacht werden. Übrigens, beginnend mit .net Core 2, müssen Sie das nicht RuntimeIdentifierim csproj einstellen.
Meziantou
26
Kann dies für .NET Core 2.0 in Visual Studio durchgeführt werden? Oder muss ich diese Befehle von Hand eingeben?
Tomasz Sikora
77
Über 60 MB für eine Hello World-Konsolen-App!
Shox
13
@mikolaj Es gibt nur eine Ziellaufzeit "portabel". Gibt es eine Möglichkeit, alle Ziele zu erreichen? Ich bin damit einverstanden, die Befehlszeile zu verwenden, denke aber, dass dies ein Schritt zurück ist.
Gsharp
10
Dadurch wird keine eigenständige ausführbare Datei erstellt. Dadurch wird eine ausführbare Datei zusammen mit einer Vielzahl anderer Dateien erstellt (im Release-Ordner meine ich). Einschließlich einiger Unterordner mit eigenen Dateien. Gibt es eine Möglichkeit, eine echte eigenständige ausführbare Datei zu erstellen ?
Matthew
121

UPDATE (31. Oktober 2019)

Für alle, die dies über eine GUI tun möchten und:

  • Verwendet Visual Studio 2019
  • Hat .NET Core 3.0 installiert (in der neuesten Version von Visual Studio 2019 enthalten)
  • Möchte eine einzelne Datei generieren

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Hinweis

Beachten Sie die große Dateigröße für eine so kleine Anwendung

Geben Sie hier die Bildbeschreibung ein

Sie können die Eigenschaft "PublishTrimmed" hinzufügen. Die Anwendung enthält nur Komponenten, die von der Anwendung verwendet werden. Achtung : Tun Sie dies nicht, wenn Sie Reflexion verwenden

Geben Sie hier die Bildbeschreibung ein

Erneut veröffentlichen

Geben Sie hier die Bildbeschreibung ein


Vorherigen Post

Für alle, die Visual Studio verwenden und dies über die GUI tun möchten, gehen Sie wie folgt vor:

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Francisco Vilches
quelle
18
Schade, dass die Ausgabe eine Reihe von Dateien enthält, nicht nur eine EXE-Datei wie das alte .NET Framework.
Tomas Karban
2
@Tomas Karban - Es war der Fall, bis ich den Bereitstellungsmodus auf "in sich geschlossen" änderte. Nach der Änderung erschien die Exe-Datei auch im Veröffentlichungsordner :-)
Mariusz
@TomasKarban .NET Core ist keine Allzweck-Laufzeit. Es wurde speziell für 1) Cloud- / Container-Bereitstellung, 2) Multi-Plattform entwickelt. Es soll auch nur vorübergehend sein - es ist nur ein "schneller" Hack, bis .NET vollständig zu Open Source gemacht werden kann. .NET 5.0 wird das nächste Allzweck-.NET sein.
Luaan
2
Trotzdem ist es lächerlich, dass die IDE für .NET einfach nicht die grundlegendsten Funktionen unterstützt, wenn Sie auf .NET Core abzielen. Und genau darauf muss jeder abzielen, um plattformübergreifende Befehlszeilenanwendungen zu erstellen - beispielsweise einen Compiler.
Stellen Sie Monica
18

Das Folgende erzeugt im Ausgabeverzeichnis:

  • alle Paketreferenzen
  • die Ausgabebaugruppe
  • die Bootstrapping-Exe

Es enthält jedoch nicht alle .NET Core-Laufzeitassemblys.

<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>

Ich habe es hier in ein Beispiel eingepackt: https://github.com/SimonCropp/NetCoreConsole

Simon
quelle
mit Ausnahme der ($ Temp) verweist auf mein c: \ Users \ xxx \ AppData \ Local \ Temp, das offensichtlich nicht entfernt / gereinigt werden kann - und es ist auch nicht ratsam, dies zu tun
Adaptabi
1
@Adaptabi Temp wird als eine Eigenschaft am Anfang des Skripts definiert
Simon
2

Wenn eine .bat-Datei akzeptabel ist, können Sie eine bat-Datei mit demselben Namen wie die DLL-Datei erstellen (und im selben Ordner ablegen) und dann den folgenden Inhalt einfügen:

dotnet %~n0.dll %*

Dies setzt natürlich voraus, dass auf dem Computer .NET Core installiert und global verfügbar ist.

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

(Diese Antwort stammt aus Chets Kommentar .)

Ambrose Leung
quelle
0

Hier ist meine hackige Problemumgehung: Generieren Sie eine Konsolenanwendung (.NET Framework), die ihren eigenen Namen und ihre eigenen Argumente liest und dann aufruft dotnet [nameOfExe].dll [args] .

Dies setzt natürlich voraus, dass .NET auf dem Zielcomputer installiert ist.

Hier ist der Code. Fühlen Sie sich frei zu kopieren!

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
quelle
6
Wenn Sie sowieso eine zusätzliche Datei haben wollen, warum nicht einfach eine Bat-Datei erstellen, die enthältdotnet [nameOfExe].dll %*
Chet