As we all know, .NET Core follows the same strategy for compiling application into an intermediate form so that it can run on multiple platforms like Windows, Linux and MacOS without recompiling the source code just like Java.
Unlike Java however, .NET Core apps can be distributed in two ways. In order to run any Java application you must have the Java Runtime Environment installed on the target machines. With .NET Core, this is optional. DotNET Core can package the runtime along with the app. We'll see how this works with a classic 'Hello World' app using DotNetCore 3.1.
Create the console application
d:\temp>md HelloWorld d:\temp>cd HelloWorld d:\temp\HelloWorld>dotnet new console d:\temp\HelloWorld>dotnet runThe last command will compile and run the app which displays Hello World! on the console.
Adding multiple targets
Microsoft uses the term 'runtime identifier' (RIDs) to target specific platforms. This page has a lot of information about how this works. I strongly suggest you go through this once. We'll add the RID for Linux (Ubuntu) to our project. Open the file HelloWorld.csproj in a text editor. The contents will look like this:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> </PropertyGroup> </Project>
We need to add <RuntimeIdentifiers>win10-x64;linux-x64</RuntimeIdentifiers>. The project file should now look like:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp3.1</TargetFramework> <RuntimeIdentifiers>win10-x64;linux-x64</RuntimeIdentifiers> </PropertyGroup> </Project>
Publishing for a platform
We need to use the dotnet publish command to publish. The -r switch allows selecting a particular RID (platform). We'll first publish targetting the Windows platform:
dotnet publish -r win10-x64
This is the output we see:
If we open the bin\Debug\netcoreapp3.1\win10-x64\publish folder in Windows Explorer, we see whole lot of files, together, all these files are enough to run the app on another Windows 10 PC which does not even have the .NET Core runtime installed.
Let's do the same for Linux.
dotnet publish -r linux-x64
The output is similar:
Again, copying all the files present in the bin\Debug\netcoreapp3.1\linux-x64\publish\ to a Ubuntu Linux machine is enough to run the app on the target Linux machine. We can actually test this out on Windows itself. One thing to keep in mind is that the generated application assembly (dll) is itself platform neutral i.e. it is capable of running on any supported operating system. Its some of the other supporting files which are platform specific.
We need to install Windows Subsystem for Linux (WSL). Its quite easily done. Refer to this link to enable WSL. If you for some reason don't want to use WSL, you can always use a real Linux machine or a VM. This post uses WSL.
Start WSL and change the directory to the Linux publish folder and run the HelloWorld application:
Note, running the dotnet command produces an error because there is no .NET Core runtime or SDK installed on the Linux subsystem. However, when we run the actual app ./HelloWorld, it executes without any error.
Framework dependent publishing
The kind of publishing we saw till now was a self-contained publishing which is great to distributing the app on systems which don't have the .NET Core runtime installed but, what if you already have the runtime? Do we still need to copy all the files on the target system?
The answer is no, we can do with a much smaller set of files. We just need to use a specific flag when publishing. First we delete the bin\Debug\netcoreapp3.1\linux-x64 folder and then run the publish command again but specify the --self-contained false flag.
dotnet publish -r linux-x64 --self-contained false
The publish folder now contains only five files. If we now copy these files to a Linux system which has the .NET Core Runtime installed, we should be able to run the app using dotnet ./HelloWorld.dll command.
The dotnet --list-runtimes command prints the runtime available on the system. Since the runtime is present, running dotnet ./HelloWorld.dll runs the app successfully. We however don't have the .NET Core SDK which is why running the dotnet --version command shows a message about not finding any SDKs.
You can also run the application another way. You can add an execute permission on the HelloWorld file by using the command chmod +x ./HelloWorld. You can now run the app by simply executing HelloWorld.
Awesome isn't it?