Zbuduj aplikację konsoli .NET Core, aby wygenerować plik EXE

413

W przypadku projektu aplikacji konsolowej ukierunkowanej na .NET Core 1.0 nie mogę dowiedzieć się, jak uzyskać plik .exe, który będzie generowany podczas kompilacji. Projekt działa poprawnie podczas debugowania.

Próbowałem opublikować projekt, ale to też nie działa. Ma to sens, ponieważ plik EXE byłby specyficzny dla platformy, ale musi istnieć sposób. Moje wyszukiwania ujawniły tylko odniesienia do starszych wersji .NET Core, które korzystały z project.json.

Za każdym razem, gdy buduję lub publikuję, to wszystko, co otrzymuję:

Zbuduj katalog

kenchilada
źródło
15
Możliwy duplikat VS2017 Kompiluj NetCoreApp jako EXE
Martin Ullrich
2
@geekzster proszę cofnij usunięcie - wiem, że nie odpowiedziałeś na pytanie OP, ale odpowiedziałeś na moje i podejrzewam, że wielu innych powiedziało dotnet <path>.dll( dotnet run <path>.dllz oczywistych powodów nie myślałem i pisałem bez sukcesu)! (Po zastanowieniu dobrze byłoby, gdyby zostało zamknięte na korzyść drugiego pytania, które ma podobny zestaw odpowiedzi)
Ruben Bartelink

Odpowiedzi:

480

Do celów debugowania można użyć pliku DLL. Możesz go uruchomić za pomocą dotnet ConsoleApp2.dll. Jeśli chcesz wygenerować plik EXE, musisz wygenerować samodzielną aplikację.

Aby wygenerować samodzielną aplikację (EXE w systemie Windows), musisz określić docelowy czas wykonywania (który jest specyficzny dla systemu operacyjnego, na który celujesz).

Tylko wersja wcześniejsza niż .NET Core 2.0 : Najpierw dodaj identyfikator środowiska wykonawczego docelowych środowisk uruchomieniowych do pliku .csproj ( lista obsługiwanych identyfikatorów RID ):

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

Powyższy krok nie jest już wymagany, począwszy od .NET Core 2.0 .

Następnie ustaw żądane środowisko wykonawcze podczas publikowania aplikacji:

dotnet publish -c Release -r win10-x64
dotnet publish -c Release -r ubuntu.16.10-x64
meziantou
źródło
15
Myślę, że można to zrobić tylko za pomocą CLI. BTW, zaczynając od .net core 2, nie musisz ustawiać RuntimeIdentifiercsproj.
meziantou
26
dla .NET Core 2.0 czy można tego dokonać w Visual Studio? Czy muszę ręcznie wpisać te polecenia?
Tomasz Sikora
77
Ponad 60 MB na aplikację konsolową Hello world!
shox
13
@mikolaj Jest tylko jeden docelowy środowisko wykonawcze „przenośne”. Czy istnieje sposób na sprowadzenie wszystkich celów? Mogę używać wiersza poleceń, ale myślę, że to krok wstecz.
gsharp
10
To nie tworzy samodzielnego pliku wykonywalnego. Tworzy to plik wykonywalny wraz z mnóstwem innych plików (mam na myśli folder wydania). W tym niektóre podfoldery z własnymi plikami. Czy istnieje sposób na stworzenie prawdziwego samodzielnego pliku wykonywalnego?
Matthew
121

AKTUALIZACJA (31-OCT-2019)

Dla każdego, kto chce to zrobić za pomocą GUI i:

  • Korzysta z programu Visual Studio 2019
  • Ma zainstalowany program .NET Core 3.0 (zawarty w najnowszej wersji programu Visual Studio 2019)
  • Chce wygenerować pojedynczy plik

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

wprowadź opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Uwaga

Zwróć uwagę na duży rozmiar pliku dla tak małej aplikacji

Wpisz opis zdjęcia tutaj

Możesz dodać właściwość „PublishTrimmed”. Aplikacja będzie zawierać tylko składniki używane przez aplikację. Uwaga : nie rób tego, jeśli używasz odbicia

Wpisz opis zdjęcia tutaj

Opublikuj ponownie

Wpisz opis zdjęcia tutaj


Poprzedni post

Dla każdego, kto używa Visual Studio i chce to zrobić za pomocą GUI, zobacz poniższe kroki:

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Wpisz opis zdjęcia tutaj

Francisco Vilches
źródło
19
Szkoda, że ​​wynikiem jest wiązka plików, a nie tylko jeden plik EXE, taki jak stary .NET Framework.
Tomas Karban
2
@Tomas Karban - Tak było, dopóki nie zmieniłem trybu wdrażania na „samodzielny”. Po zmianie pliku exe pojawił się również w folderze publikowania :-)
Mariusz
@TomasKarban .NET Core nie jest środowiskiem uruchomieniowym ogólnego przeznaczenia. Jest specjalnie zaprojektowany do 1) wdrażania w chmurze / kontenerze, 2) na wielu platformach. Ma również być tymczasowy - to tylko „szybki” hack, dopóki cała platforma .NET nie stanie się open source. .NET 5.0 będzie kolejnym .NET ogólnego przeznaczenia.
Luaan,
3
To jednak niedorzeczne, że IDE dla .NET po prostu nie obsługuje najbardziej podstawowych funkcji, gdy celujesz w .NET Core. I do tego wszyscy muszą dążyć, aby tworzyć wieloplatformowe aplikacje wiersza poleceń - powiedzmy, kompilator.
Przywróć Monikę
18

Poniższe spowoduje wygenerowanie w katalogu wyjściowym

  • wszystkie odwołania do pakietów
  • zespół wyjściowy
  • exe ładowania początkowego

Ale nie zawiera wszystkich zestawów środowiska uruchomieniowego .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>

Zrobiłem to w próbce tutaj: https://github.com/SimonCropp/NetCoreConsole

Szymon
źródło
z wyjątkiem punktów ($ Temp) do mojego c: \ Users \ xxx \ AppData \ Local \ Temp, których oczywiście nie można usunąć / wyczyścić - ani nie jest to zalecane
Adaptabi
1
@Adaptabi Temp jest zdefiniowany jako właściwość na początku skryptu
Simon
2

Jeśli plik .bat jest akceptowalny, możesz utworzyć plik nietoperza o tej samej nazwie co plik DLL (i umieścić go w tym samym folderze), a następnie wkleić następującą treść:

dotnet %~n0.dll %*

Oczywiście zakłada to, że komputer ma zainstalowany program .NET Core i jest dostępny na całym świecie.

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

(Ta odpowiedź pochodzi z komentarza Cheta ).

Ambrose Leung
źródło
0

Oto moje hacky obejście - wygeneruj aplikację konsolową (.NET Framework), która odczyta własną nazwę i argumenty, a następnie wywoła dotnet [nameOfExe].dll [args].

Oczywiście zakłada to, że .NET jest zainstalowany na maszynie docelowej.

Oto kod. Nie krępuj się skopiować!

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
źródło
6
Jeśli i tak będziesz mieć dodatkowy plik, dlaczego nie utworzyć pliku nietoperza, który zawieradotnet [nameOfExe].dll %*
Chet