How to make a WinForms app with .NET 5 entirely from the command line and publish as one self-contained file
I got a lovely email from a reader named Steven who has been doing .NET for many years and is excited about .NET 5. He has an interesting perspective:
I really like the .NET library.
During 2020, I've taught myself enough Windows Forms to write my own JPG photo viewer. Sorry but I'm not a fan of XAML, so I just write and compile raw Windows forms in C#.
Now before we start, I would offer that XAML is how you express your UI in WPF, and there is a WinForms designer for .NET Core in the latest version of Visual Studio so if you do want to mix and match using a designer and also writing your WinForms straight you can do that these days.
Steven asks:
I wonder if you could help me with a good recipe for command line compile on C#9 / .NET 5 to make a .exe?
More specifically he adds:
I want to be able to:
- from a command line
- without Visual Studio
- create a standalone .exe file for Windows
- from csharp myprog.cs
- where I don't mind if installing the Windows .NET runtime is a prerequisite
- Using C# 9 and .NET 5
Cool, I can help with that. Using only the .NET 5 SDK which you can install from http://www.dot.net, you can make a single EXE that will run on any Windows Machine in two commands, assuming you are already in a new empty folder.
~\Desktop\forsteven>
dotnet new winforms
The template "Windows Forms App" was created successfully.
Processing post-creation actions...
Running 'dotnet restore' on C:\Users\scott\Desktop\forsteven\forsteven.csproj...
Determining projects to restore...
Restored C:\Users\scott\Desktop\forsteven\forsteven.csproj (in 56 ms).
Restore succeeded.
~\Desktop\forsteven>
dotnet publish -r win-x64 /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
Microsoft (R) Build Engine version 16.8.0+126527ff1 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
Restored C:\Users\scott\Desktop\forsteven\forsteven.csproj (in 94 ms).
forsteven -> C:\Users\scott\Desktop\forsteven\bin\Debug\net5.0-windows\win-x64\forsteven.dll
forsteven -> C:\Users\scott\Desktop\forsteven\bin\Debug\net5.0-windows\win-x64\publish\
First I say dotnet new winforms
which is the command line equivalent for "File | New Project in Visual Studio.
Next I dotnet publish -r win-x64 /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
which is a little extra with that last bit, but look at the design for the single file feature you'll see that if you want all the native libraries linked in you have suck in more.
Personally, I think that the last two in the list should just be one. It's not obvious but it turns out it's quite hard as you move into things like WinForms that require some native libraries. Those native libraries don't like being run while embedded in an EXE. To solve this, you can either use IncludeAllContentForselfExtract or IncludeNativeLibrariesForSelfExtract.
Self-Contained Publish
- Normal publish:
dotnet publish -r win-x64
- Published files:
HelloWorld.exe
,HelloWorld.pdb
, and 224 more files- Single-file publish Linux:
dotnet publish -r linux-x64 /p:PublishSingleFile=true
- Published files:
HelloWorld
,HelloWorld.pdb
- Single-file publish Windows:
dotnet publish -r win-x64 /p:PublishSingleFile=true
- Published files:
HelloWorld.exe
,HelloWorld.pdb
,coreclr.dll
,clrjit.dll
,clrcompression.dll
,mscordaccore.dll
- Single-file publish Windows with Extraction:
dotnet publish -r win-x64 /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
- Published files:
HelloWorld.exe
,HelloWorld.pdb
So that "WithExtraction" means things get unzipped and run, while the other Single File isn't really single file (because some native bits are outside) but it avoids the temporary directory and just unfolds into memory. So it's more "Single small folder."
The resulting app is one 145 meg EXE that can be run anywhere without installing .NET 5 because we included it all in the EXE.
You can also add /p:PublishTrimmed=true
and it's just 83 megs, again, just one EXE.
Hope this helps!
Sponsor: Need a multi-cluster load balancer and API gateway? Try VoltMesh: built for modern and distributed apps that require automation, performance and visibility. Start for free today.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
from csharp myprog.csAnd unlike what the blog title says, you didn't make an "app", just an EXE file that does nothing.
Steven's email is altogether curious. He says "I just write and compile raw Windows forms in C#". In that case, he must already know everything you've explained here because that's the only way to "write and compile raw Windows forms in C#".
I use msbuild to build my Xamarin projects from the command line. That works great.
If you want to use dotnet, you'll have to wait until .NET6 is released. Xamarin couldn't make it for .NET5 and moved their target to .NET6. Some things already work. You can find some samples at https://github.com/xamarin/net6-samples
You are missing the point. This 145 MB (83 MB when using trimming) include all the needed files for .NET (Garbage collector, JIT, ...) If you used Java for your application maybe you could get a smaller JAR file, but then again you would need to install the JVM on your machine (and it is a lot more than 145 MB).
This is great!! I've been working with the .NET Framework for more than 15 years and this feature alone is huge. No more "please install at least .NET Framework 4.7.2 on your machines"
Static linking where there is only one .exe file and not a self extracting set of libraries
Ability to create C# lib files like C++ (not just dll files) to let us distribute just the code needed and not a dll.
loved the usual information a person provide to your visitors?
Is gonna be back often in order to inspect new posts
Comments are closed.