Bangun aplikasi .NET Core console untuk menghasilkan EXE

414

Untuk proyek aplikasi konsol yang menargetkan .NET Core 1.0, saya tidak tahu cara mendapatkan .exe ke output saat membangun. Proyek ini berjalan dengan baik dalam debug.

Saya sudah mencoba menerbitkan proyek, tetapi itu tidak berhasil. Masuk akal karena file EXE akan spesifik platform, tetapi harus ada caranya. Pencarian saya hanya menghasilkan referensi ke .NET Core versi lama yang menggunakan project.json.

Setiap kali saya membangun atau menerbitkan, ini yang saya dapatkan:

Bangun direktori

kenchilada
sumber
15
Kemungkinan duplikat dari VS2017 Kompilasi NetCoreApp sebagai EXE
Martin Ullrich
2
@geekzster tolong batalkan penghapusan - Saya tahu Anda tidak menjawab pertanyaan OP, tetapi Anda menjawab pertanyaan saya, dan saya curiga ada banyak orang yang mengatakan dotnet <path>.dll(Saya tidak berpikir dan mengetik dotnet run <path>.dlltanpa berhasil karena alasan yang jelas)! (Kalau dipikir-pikir akan lebih baik jika ini ditutup untuk pertanyaan lain yang memiliki jawaban yang serupa)
Ruben Bartelink

Jawaban:

480

Untuk keperluan debugging, Anda dapat menggunakan file DLL. Anda dapat menjalankannya menggunakan dotnet ConsoleApp2.dll. Jika Anda ingin membuat file EXE, Anda harus membuat aplikasi mandiri.

Untuk menghasilkan aplikasi mandiri (EXE di Windows), Anda harus menentukan runtime target (yang khusus untuk sistem operasi yang Anda targetkan).

Khusus Pre-.NET Core 2.0 : Pertama, tambahkan pengidentifikasi runtime dari target runtimes di file .csproj ( daftar RID yang didukung ):

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

Langkah di atas tidak lagi diperlukan dimulai dengan .NET Core 2.0 .

Kemudian, atur runtime yang diinginkan ketika Anda menerbitkan aplikasi Anda:

dotnet publish -c Release -r win10-x64
dotnet publish -c Release -r ubuntu.16.10-x64
meziantou
sumber
15
Saya pikir ini hanya dapat dilakukan dengan CLI. BTW, dimulai dengan .net core 2, Anda tidak perlu mengatur RuntimeIdentifiercsproj.
meziantou
26
untuk .NET Core 2.0 dapatkah ini dilakukan di Visual Studio? Atau saya harus mengetik perintah ini dengan tangan?
Tomasz Sikora
77
Lebih dari 60MB untuk aplikasi konsol Hello World!
shox
13
@mikolaj Hanya ada satu target runtime "portable". Apakah ada cara untuk memasukkan semua target? Saya setuju dengan menggunakan baris perintah, namun berpikir itu adalah langkah mundur.
gsharp
10
Ini tidak membuat eksekusi mandiri. Ini membuat executable, bersama dengan sejumlah file lain (dalam folder rilis yang saya maksud). Termasuk beberapa subfolder dengan file mereka sendiri. Apakah ada cara untuk membuat eksekusi mandiri yang benar ?
Matius
122

UPDATE (31-OCT-2019)

Bagi siapa pun yang ingin melakukan ini melalui GUI dan:

  • Menggunakan Visual Studio 2019
  • Telah .NET Core 3.0 diinstal (termasuk dalam versi terbaru dari Visual Studio 2019)
  • Ingin menghasilkan satu file

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Catatan

Perhatikan ukuran file besar untuk aplikasi sekecil itu

Masukkan deskripsi gambar di sini

Anda dapat menambahkan properti "PublishTrimmed". Aplikasi hanya akan menyertakan komponen yang digunakan oleh aplikasi. Perhatian : jangan lakukan ini jika Anda menggunakan refleksi

Masukkan deskripsi gambar di sini

Publikasikan lagi

Masukkan deskripsi gambar di sini


Posting Sebelumnya

Bagi siapa pun yang menggunakan Visual Studio dan ingin melakukan ini melalui GUI, lihat langkah-langkah di bawah ini:

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Masukkan deskripsi gambar di sini

Francisco Vilches
sumber
19
Sayang sekali hasilnya adalah banyak file, bukan hanya satu EXE seperti .NET Framework.
Tomas Karban
2
@ Thomas Karban - Itu yang terjadi sampai saya mengubah mode penyebaran menjadi "mandiri" Setelah perubahan file exe muncul di folder publik juga :-)
Mariusz
@TomasKarban .NET Core bukan runtime tujuan umum. Ini dirancang khusus untuk 1) penyebaran cloud / kontainer, 2) multi-platform. Ini juga dimaksudkan untuk sementara - ini hanya peretasan "cepat" sampai semua .NET dapat dibuat open source. .NET 5.0 akan menjadi tujuan umum berikutnya .NET.
Luaan
3
Namun, konyol bahwa IDE untuk .NET tidak mendukung fungsi paling dasar saat Anda menargetkan .NET Core. Dan itulah yang setiap orang harus target untuk membuat aplikasi baris perintah lintas platform - katakanlah, sebuah kompiler.
Pasang kembali Monica
18

Berikut ini akan menghasilkan, di direktori output,

  • semua referensi paket
  • perakitan output
  • exe bootstrap

Tapi itu tidak mengandung semua .NET Core runtime assemblies.

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

Saya membungkusnya dalam sampel di sini: https://github.com/SimonCropp/NetCoreConsole

Simon
sumber
kecuali ($ Temp) menunjuk ke c saya: \ Users \ xxx \ AppData \ Local \ Temp yang jelas tidak dapat dihapus / dibersihkan - juga tidak disarankan untuk melakukannya
Adaptabi
1
@Adaptabi Temp didefinisikan sebagai properti di awal skrip
Simon
2

Jika file .bat dapat diterima, Anda dapat membuat file bat dengan nama yang sama dengan file DLL (dan menempatkannya di folder yang sama), lalu menempelkan konten berikut:

dotnet %~n0.dll %*

Jelas, ini mengasumsikan bahwa mesin telah. NET Core diinstal dan tersedia secara global.

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

(Jawaban ini berasal dari komentar Chet .)

Ambrose Leung
sumber
0

Inilah solusi untuk saya - buat aplikasi konsol (.NET Framework) yang bertuliskan nama dan argumennya sendiri, lalu panggil dotnet [nameOfExe].dll [args].

Tentu saja ini mengasumsikan bahwa .NET diinstal pada mesin target.

Ini kodenya. Silakan menyalin!

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
sumber
6
Jika Anda akan memiliki file tambahan, mengapa tidak membuat file bat yang berisidotnet [nameOfExe].dll %*
Chet