479

For a console application project targeting .NET Core 1.0, I cannot figure out how to get an .exe to output during build. The project runs fine in debug.

I've tried publishing the project, but that does not work either. It makes sense since an EXE file would be platform-specific, but there must be a way. My searches have only turned up reference to older .NET Core versions that used project.json.

Whenever I build or publish, this is all I get:

Build directory

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kenchilada
  • 7,469
  • 5
  • 25
  • 34
  • 15
    Possible duplicate of [VS2017 Compile NetCoreApp as EXE](http://stackoverflow.com/questions/44038847/vs2017-compile-netcoreapp-as-exe) – Martin Ullrich May 19 '17 at 16:20
  • 2
    @geekzster please undelete - I know you didnt answer the OP question, but you answered mine, and I suspect that of many others by saying `dotnet .dll` (I was not thinking and typing `dotnet run .dll` without success for obvious reasons) ! (On reflection it would be good if this was closed in favor of the other question which has a similar set of answers) – Ruben Bartelink Oct 31 '18 at 09:14
  • someone please help me https://stackoverflow.com/q/69914473/1225672 – aldo Nov 13 '21 at 07:32

5 Answers5

539

For debugging purposes, you can use the DLL file. You can run it using dotnet ConsoleApp2.dll. If you want to generate an EXE file, you have to generate a self-contained application.

To generate a self-contained application (EXE in Windows), you must specify the target runtime (which is specific to the operating system you target).

Pre-.NET Core 2.0 only: First, add the runtime identifier of the target runtimes in the .csproj file (list of supported RIDs):

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

The above step is no longer required starting with .NET Core 2.0.

Then, set the desired runtime when you publish your application:

dotnet publish -c Release -r win10-x64
dotnet publish -c Release -r ubuntu.16.10-x64
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
meziantou
  • 20,589
  • 7
  • 64
  • 83
  • 1
    Is there a way to do this in "Visual Studio for Mac"? Or can this be done only through the CLI? – tedi Sep 14 '17 at 09:33
  • 15
    I think this can be done only with the CLI. BTW, starting with .net core 2, you don't need to set the `RuntimeIdentifier` in the csproj. – meziantou Sep 14 '17 at 13:52
  • 1
    Thanks! Looks like it works without the RuntimeIdentifiers. Nice, so that i have to type all those only once in a shell script. :) They should make something like this possible: `dotnet publish -c Release -r win10-x64,ubuntu.16.10-x64` – tedi Sep 15 '17 at 07:22
  • 31
    for .NET Core 2.0 can this be done in Visual Studio? Or I must type these commands by hand? – Tomasz Sikora Oct 21 '17 at 14:16
  • 6
    right click on the project, Publish and set the target runtime to the desired environment and output path. But the x64 targets will be bloated! – mikolaj Nov 04 '17 at 04:46
  • 88
    Over 60MB for a Hello world console app! – shox Jan 23 '18 at 05:16
  • 13
    @mikolaj There's just one target runtime "portable". Is there a way to bring all the targets in? I'm ok with to use the command line, however think that's a step back. – gsharp Jan 24 '18 at 07:35
  • 5
    I got tired of coming back here for the command-line arguments, so I made a simple GUI for anyone looking for one. Feel free to improve; this was only about 30 minutes of work/testing. https://github.com/spacekh/DotNetPublish – Kristen Hammack May 02 '18 at 16:15
  • On .net core 2.1, this was the fix for error: NETSDK1031: It is not supported to build or publish a self-contained application without specifying a RuntimeIdentifier – JsAndDotNet Oct 04 '18 at 09:52
  • 6
    @shox See [this](https://ianqvist.blogspot.com/2018/01/reducing-size-of-self-contained-net.html) on how to reduce the app size. – Nae Oct 12 '18 at 11:32
  • 1
    You can publish from visual studio, no command line needed, right click project select publish – jjxtra Feb 01 '19 at 20:43
  • just as an update for the app size problem, it was fixed in the last few versions of VS, and you now get a very slim exe file. – BgrWorker Feb 06 '19 at 19:56
  • An easier way to not have to remember this is to stuff it in a batch file. You don't need a project for this. – Chris Feb 09 '19 at 16:16
  • 13
    This doesn't create a standalone executable. This creates an executable, along with a host of other files (in the release folder I mean). Including some subfolders with their own files. Is there a way to create a true __standalone__ executable? – Matthew Feb 13 '19 at 18:50
  • This has the full list of supported runtimes: https://github.com/dotnet/corefx/blob/master/pkg/Microsoft.NETCore.Platforms/runtime.json – Crouching Kitten Mar 09 '19 at 13:53
  • 1
    I created a post build script to do exactly this. It created a fork bomb. Just FYI be careful – user1529413 May 20 '19 at 12:39
  • @shox That is because the Runtime is included. Add `--self-contained false` to publish without the .NET Core Runtime. Of course, that means the Runtime needs to be installed on your target device. – asdf Jun 18 '19 at 12:48
  • 7
    You have got to be kidding me. Huge, expensive IDE, and I have to open a damned console window to generate an EXE? No way. – Triynko Aug 08 '19 at 18:59
  • 1
    @Triynko There is a GUI for that in Visual Studio. In any case, there's not much point in using .NET Core to develop standard Windows applications. – Luaan Aug 12 '19 at 10:33
  • 1
    In addition to [meziantou's answer](https://stackoverflow.com/a/44074296/11931717) When I run: dotnet publish -c Release -r win10-x64 I got a folder named win10-x64 with an exe and another folder inside it, When I installed the service, i pointed to this exe. but it gave me this error, I looked around, and found that the folder win10-x64/publish, also had an exe, when I pointed to this exe instead, I'm able to boot the service without any errors. – NiclasAndersen Aug 15 '19 at 12:55
  • @mljli over a year later, but to be fair, it worked, so thanks lol. I noticed it generated a pdb file in the same directory as the executable but it still ran even after I deleted it, so that's good. – Matthew Apr 29 '20 at 17:44
  • 1
    Ok, so how do I add publishing step (for selected environments) to a build process so I don't need a manual step? I need this to be working in CI. FYI: If I add the above mentioned command to Post-Build step I get infinite loop and build never ends. – Radek Strugalski May 29 '20 at 12:08
205

UPDATE: FEB2022 The below still holds for .NET 6

UPDATE for .NET 5!

The below applies on/after NOV2020 when .NET 5 is officially out.

(see quick terminology section below, not just the How-to's)

How-To (CLI)

Pre-requisites

  • Download latest version of the .net 5 SDK. Link

Steps

  1. Open a terminal (e.g: bash, command prompt, powershell) and in the same directory as your .csproj file enter the below command:
dotnet publish --output "{any directory}" --runtime {runtime}
  --configuration {Debug|Release} -p:PublishSingleFile={true|false}
  -p:PublishTrimmed={true|false} --self-contained {true|false}

example:

dotnet publish --output "c:/temp/myapp" --runtime win-x64 --configuration Release
  -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained true

How-To (GUI)

Pre-requisites

  • If reading pre NOV2020: Latest version of Visual Studio Preview*
  • If reading NOV2020+: Latest version of Visual Studio*

*In above 2 cases, the latest .net5 SDK will be automatically installed on your PC.

Steps

  1. Right-Click on Project, and click Publish
    enter image description here

  2. Click Start and choose Folder target, click next and choose Folder Choose Folder Target

  3. Enter any folder location, and click Finish

  4. Click on Edit
    enter image description here

  5. Choose a Target Runtime and tick on Produce Single File and save.* enter image description here

  6. Click Publish

  7. Open a terminal in the location you published your app, and run the .exe. Example: enter image description here

A little bit of terminology

Target Runtime
See the list of RID's

Deployment Mode

  • Framework Dependent means a small .exe file produced but app assumed .Net 5 is installed on the host machine
  • Self contained means a bigger .exe file because the .exe includes the framework but then you can run .exe on any machine, no need for .Net 5 to be pre-installed. NOTE: WHEN USING SELF CONTAINED, ADDITIONAL DEPENDENCIES (.dll's) WILL BE PRODUCED, NOT JUST THE .EXE

Enable ReadyToRun compilation
TLDR: it's .Net5's equivalent of Ahead of Time Compilation (AOT). Pre-compiled to native code, app would usually boot up faster. App more performant (or not!), depending on many factors. More info here

Trim unused assemblies
When set to true, dotnet will generate a very lean and small .exe and only include what it needs. Be careful here. Example: when using reflection in your app you probably don't want to set this flag to true.

Microsoft Doc


Francisco Vilches
  • 3,426
  • 1
  • 15
  • 18
  • 23
    Too bad the output is a bunch of files, not just one EXE like the old .NET Framework. – Tomas Karban Apr 29 '19 at 15:29
  • 3
    @Tomas Karban - It was the case until I changed deployment mode to "self-contained" After change exe file appeared in the publish folder also :-) – Mariusz Jun 18 '19 at 15:44
  • @TomasKarban .NET Core is not a general purpose runtime. It's specifically designed for 1) cloud/container deployment, 2) multi-platform. It's also meant to be temporary - it's just a "quick" hack until all of .NET can be made open source. .NET 5.0 is going to be the next general purpose .NET. – Luaan Aug 12 '19 at 10:39
  • 1
    This did not work for me. I tried many combinations and my executable simply will not display the contents of my program, a very simple one, Hello World. Did something change in a year? – Katherine Oct 08 '20 at 21:28
  • It did not work for me until I removed the `--configuration` flag. – Shad Sep 15 '21 at 19:44
20

The following will produce, in the output directory,

  • all the package references
  • the output assembly
  • the bootstrapping exe

But it does not contain all .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>

I wrapped it up in a sample here: https://github.com/SimonCropp/NetCoreConsole

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Simon
  • 33,714
  • 21
  • 133
  • 202
  • 1
    except the ($Temp) points to my c:\Users\xxx\AppData\Local\Temp which obviously cannot be removed/cleaned - nor it is adviceable to do so – DATEx2 Jul 09 '19 at 12:13
  • 1
    @Adaptabi Temp is defines as a property at the start of the script – Simon Jul 18 '19 at 01:01
4

If a .bat file is acceptable, you can create a bat file with the same name as the DLL file (and place it in the same folder), then paste in the following content:

dotnet %~n0.dll %*

Obviously, this assumes that the machine has .NET Core installed and globally available.

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

(This answer is derived from Chet's comment.)

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Ambrose Leung
  • 3,704
  • 2
  • 25
  • 36
0

Here's my hacky workaround - generate a console application (.NET Framework) that reads its own name and arguments, and then calls dotnet [nameOfExe].dll [args].

Of course this assumes that .NET is installed on the target machine.

Here's the code. Feel free to copy!

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();
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ambrose Leung
  • 3,704
  • 2
  • 25
  • 36
  • 7
    If you are going to have an additional file anyway, why not just create a bat file that contains `dotnet [nameOfExe].dll %*` – Chet Feb 27 '19 at 00:36