.NET Core - How to publish a self-contained application (.exe)


The idea of this article is to detail how to create a .NET Core Console application from the command line tool (.NET CLI - DOTNET Command Line Interface) and the Visual Studio Code.

 

The first step is to download the .NET Core SDK. Observe that it is possible to download it to multiple platforms, as for example:

 

  • Windows
  • Linux (RHEL, Ubuntu, Linux Mint, Debian, Fedora, CentOS, Oracle Linux and openSUSE)
  • Mac
  • Docker

 

The .NET Core SDK provides a set of libraries and tools to create applications and .NET Core libraries. After installation, by default, the .NET SDK is located in C:\Program Files\dotnet\SDK. Observe that in that resource the versions of .NET Core are installed side-by-side:

 

 

dotnetSDK

 

 

modularThe .NET Core is based on a set of NuGet packages that allows you to optimize the applications to be dependent on only the necessary modules. This reduces the time required to test and deploy updates that are not used by the application.

Because the .NET Framework features are grouped under NuGet packages, the update time and delivery of these packages is much lower. It is not necessary to wait for a framework upgrade as a whole.

 

The NuGet packages installed by .NET Core SDK, are available for use in the .nuget\packages directory under the user profile:

 

nugetpackages

 

 

To create a new application using the command line, open the command prompt (or PowerShell) and create a directory:

mkdir C:\temp\HelloWorldConsole

cd .\Temp\HelloWorldConsole

 

The .NET Core SDK provides a command-line tool (.NET Core CLI) through the executable (also called driver) dotnet. To list the commands available for the tool, type:

dotnet -h

 

Note that there are, by default, the following commands available:

 

clicomoncommmands

 

To create a new application type Console you must use the new command. To list the types of projects that the command offers, enter the following command:

dotnet new -h

 

Notice that the new command provides the option to choose the language (C # or F #) through the -l parameter, and the type of project, through the -t parameter as:

 

newoptions

The types of projects available for .NET CLI are:
  • Console
  • web
  • lib
  • xunittest
To create a new console application, type the following command:

 

dotnet new -t console

 

The following files are created:
  • Program.cs
  • project.json

 

The Program.cs file contains the application source code:

 


namespace ConsoleApplication
{
    public class Program
    {
        public static void Main (string [] args)
        {
            Console.WriteLine ( "Hello World!");
        }
    }
}

 

Note that the code is the same as the traditional C# console application. In addition, the project.json file contains all the build information, dependencies and runtimes used by the application:

 


{
    "Version", "1.0.0- *"
    "BuildOptions": {
        "DEBUGTYPE": "portable", // reports will be generated if debugging information
        "EmitEntryPoint": true // tells whether the module contains an entry for the MAIN method
    },
    "Dependencies": {}, // informs the project dependencies
    "Frameworks": {
        "Netcoreapp1.0": {// tells you what is the application framework
            "Dependencies": {
                "Microsoft.NETCore.App": {//super set that contains the .NET Standard Library and standard library
                    "Type": "platform", // tells the machine framework will be used
                    "Version", "1.0.1"
                }
            },
            "Imports": "dnxcore50"
        }
    }
}

 

The next step is to restore the dependencies, using the following command to download the Internet NuGet libraries to the default cache directory of NuGet libraries (%USERPROFILE%\nuget\packages\ or $env:UserProfile\.nuget\packages\). If there is no internet connection, the CACHE directory will be used.

 

dotnet restore

 

After restoring the libraries, the project.lock.json file is generated with the application of references:

 


{
    "Locked": false,
    "Version": 2
    "Targets": {
        ".NETCoreApp, Version = v1.0": {
        "Libuv / 1.9.0": {
            "Type": "package"
            "Dependencies": {
                "Microsoft.NETCore.Platforms": "1.0.1"
            },
            "RuntimeTargets": {
                "Runtimes / osx / native /_._": {
                    "AssetType": "native"
                    "Rid": "osx"
                }
            }
        },
        "Microsoft.CodeAnalysis.Analyzers / 1.1.0": {
            "Type": "package"
        },
        "Microsoft.CodeAnalysis.Common / 1.3.0": {
            "Type": "package"
            "Dependencies": {
                "Microsoft.CodeAnalysis.Analyzers" "1.1.0"
                "System.AppContext" "4.1.0"
                "System.Collections": "4.0.11"
                "System.Collections.Concurrent": "4.0.12"
                "System.Collections.Immutable" "1.2.0"
                // ... And several other references omitted here because of the amount

 

To compile the application use the command:

 

dotnet build

 

By default, this command will compile the application in Debug mode. To compile in RELEASE mode, use the parameter:

 

dotnet build -c release

 

The application will be compiled in the following directory, as the netcoreapp1.0 is the selected standard framework (.NET Core):

 

.\Bin\release\netcoreapp1.0\HelloWorldConsole.dll

 

To add the FULL .NET Framework (traditional part of the operating system), add the reference "net461" as:

 


{
    "Version", "1.0.0- *"
    "BuildOptions": {
        "DEBUGTYPE": "portable", // reports will be generated if debugging information
        "EmitEntryPoint": true // tells whether the module contains an entry for the MAIN method
    },
    "Dependencies": {}, // informs the project dependencies
    "Frameworks": {
        "Net461": {},
        "Netcoreapp1.0": {// tells you what is the application framework
            "Dependencies": {
                "Microsoft.NETCore.App": { 
                    "Type": "platform", // tells the machine framework will be used
                    "Version", "1.0.1"
                }
            },
            "Imports": "dnxcore50"
        }
    }
}

 

Browse the C:\Temp\HelloWorldConsole\bin\release and note that the following folders exist for each .NET Framework version:

 

  • net461
  • netcoreapp1.0

 

To run the project, type the following command:

 

dotnet run

 

To publish the application, i.e, package the application and its dependencies in a folder, type the following command:

 

dotnet publish -c release

 

As I am using two frameworks (.NET Core and Full .NET Framework) in the project.json, it will be published two directories for the respective frameworks:

 

  • C:\Temp\HelloWorldConsole\bin\release\netcoreapp1.0\publish
  • C:\Temp\HelloWorldConsole\bin\release\net461\win7-x64\publish

 

Note that in the .NET Framework Full directory (Traditional - C:\Temp\HelloWorldConsole\bin\release\net461\win7-x64\publish), it generates the following executable:

 

HelloWorldConsole.exe

 

The same is not true for the .NET Core directory (C:\Temp\HelloWorldConsole\bin\release\netcoreapp1.0\publish), which is generated DLL instead of:

 

HelloWorldConsole.dll

 

In this case, to launch the application, you must use the command:

 

dotnet HelloWorldConsole.dll

 

This can be explained by the project.json file, where the type element ("type": "platform"), of the NET Core dependency (netcoreapp1.0), is configured to use the framework of the machine:

 


"Netcoreapp1.0": {// tells you what is the application framework
    "Dependencies": {
    "Microsoft.NETCore.App": {//superset that contains the .NET Standard Library and standard library
        "Type": "platform", // tells the machine framework will be used
        "Version", "1.0.1"
    }
},

 

To be generated an executable rather than a DLL, to allow the application to be self-contained (independent of the framework installed on the machine), you must remove the element "type": "platform":

 


    "Netcoreapp1.0": {// tells you what is the application framework
    "Dependencies": {
        "Microsoft.NETCore.App": {//superset that contains the .NET Standard Library and standard library
        "Version", "1.0.1"
    }
},

 

In this case, you must add the runtimes that the application should be compiled by add the tab runtimes. Example to compile the application for Windows and Ubuntu:

 


{
    "Version", "1.0.0- *"
    "BuildOptions": {
        "DEBUGTYPE": "portable", // reports will be generated if debugging information
        "EmitEntryPoint": true // tells whether the module contains an entry for the MAIN method
    },
    "Dependencies": {}, // informs the project dependencies
    "Frameworks": {
        "Net461": {},
        "Netcoreapp1.0": {// tells you what is the application framework
            "Dependencies": {
                "Microsoft.NETCore.App": {// 
                    "Version", "1.0.1"
                }
            },
            "Imports": "dnxcore50"
        }
    },
    "runtimes": { 
    "win7-x64": {}, 
    "ubuntu.14.04-x64": {} 
    } 
}

 

After saving the changes, you must restore the project dependencies by running:

 

dotnet restore

 

To publish the application, run the following command:

 

dotnet publish -c release

 

Note that now the executable has been generated, as well as all application dependencies (including framework DLLs) were added to the publish folder:

selfcontained

To reduce the number of dependencies, we can change the framework for the "netstandard1.6" that is a subset of netcoreapp1.0 (which includes the .NET CLR and .NET Core Core Library). The framework and the dependencies would be as follows:


{
    "version": "1.0.0-*",
    "buildOptions": {
        "debugType": "portable",
        "emitEntryPoint": true
    },
    "dependencies": {
        "NETStandard.Library": "1.6.0",
        "Microsoft.NETCore.Runtime.CoreCLR": "1.0.2",
        "Microsoft.NETCore.DotNetHostPolicy":  "1.0.1"
    },
    "frameworks": {
        "netstandard1.6": { }
    },
    "runtimes": {
        "win10-x64": {},
        "osx.10.10-x64": {}
    }
}

Note that the amount was reduced to DLLs:

netstandard

 

As it is Hello World application, you can further reduce the amount of dependencies:


{
    "version": "1.0.0-*",
    "buildOptions": {
        "debugType": "portable",
        "emitEntryPoint": true
    },
    "dependencies": {
        "System.Console": "4.0.0",
        "Microsoft.NETCore.Runtime.CoreCLR": "1.0.2",
        "Microsoft.NETCore.DotNetHostPolicy":  "1.0.1"
    },
    "frameworks": {
    "netstandard1.6": { }
    },
    "runtimes": {
        "win10-x64": {},
        "osx.10.10-x64": {}
    }
}

Note that the amount was reduced again to DLLs:

system

I hope you enjoyed.

References:

Comments (15)

  1. This is extremely helpful - Thanks!

    Just an FYI - your blogging tool has mangled a number of your json files with "pretty" quotes and misplaced capitalizations.

    1. Thank you Christopher for your great feedback and to let me know about the issues. 🙂

  2. Muy buen articulo, te importa si lo traduzco para el público español y lo publico en mi blog, eltrasterotecnologico.com, por supuesto poniendo un enlace al texto original.

    1. Me alegro que os haya gustado.

      That would be great have that article published in Spanish language.
      In addiction, I published a new one about how to starting using GIT on VSCODE and VSTS. Feel free to use it.

      .NET Core – Getting started with GIT and VSCode via Visual Studio Team Services https://blogs.technet.microsoft.com/pfelatam/2016/10/19/net-core-getting-started-with-git-and-vscode-via-visual-studio-team-services

      Saludos.

  3. Gonçalo Redondo says:

    As Christopher Lewis said please check the "misplaced capitalizations"

    For instance this is incorrect:

    "Runtimes": {
    "Win7-x64": {},
    "Ubuntu.14.04-x64": {}
    }

    it should be

    "runtimes": {
    "win7-x64": {},
    "ubuntu.14.04-x64": {}
    }

    Nice article but small errors like these can send anyone troubleshooting the wrong way. I did.

    1. Perfect. Thanks for your great feedback!
      I updated there. 🙂

      Regards,

  4. Doug says:

    How would one do this using the latest VS 2017 with the XML-based csproj format. What I've tried still doesn't seem to be creating a self-contained .exe and I cannot find a new example of this unfortunately.

    1. Hi Doug!
      Take a look at the session Self-contained deployments (SCD) of this article: https://docs.microsoft.com/en-us/dotnet/articles/core/preview3/deploying/
      Let me know if it helps.
      Regards.

      1. Doug says:

        Yes thanks! That worked great!

  5. yongduan says:

    How to use web deploy publish a self-contained website to server IIS?
    Thanks!

    1. Hi Yong,

      What is the .NET Core version that you are using?

      If you are using the version before 1.0.1, i.e., the version that has the project.json, please take a look in the following post where I show how to create a self-contained package for a console application. The concept is the same to a Web Application. After having the exe file, you can copy the package using the file option of the Web Deploy. Don't forget to change the web.config of your application to refer your executable direct, instead of dotnet.exe yourapplication.dll

      .NET Core – How to publish a self-contained application (.exe)
      https://blogs.msdn.microsoft.com/luisdem/2016/10/11/net-core-how-to-publish-a-self-contained-application-exe/

      1. yongduan says:

        Thanks reply!Maybe I'm English very poor!Not use “dotnet publish -c release -r win81-x64” command to output SCD.
        Means,how to publish Self-contained deployments (SCD) applications to remote server IIS with Web Deploy in Visual Studio?
        Use Visual Studio right click solution,publish,select web deploy,publish to remote server?by default,publish to server file not have .exe!
        Thanks!

      2. yongduan says:

        attachment:pic.twitter.com/CUk5yaiZU5

  6. Aniket Agrawal says:

    Great help!!

    How do I generate models and DbSet from the existing database. I'm using Angular-Core1.1 template with VS2017.

    Thanks

  7. Wow! just amazing article written by @Luis, Thank you so much for inspiring us from your good work, These kind of work really motivate us to work harder day by day. Thank you so much for great post.

Skip to main content