Scott Hanselman

How to make a WinForms app with .NET 5 entirely from the command line and publish as one self-contained file

November 19, 2020 Comment on this post [14] Posted in DotNetCore | Open Source | Windows Client
Sponsored By

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.

image

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.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
November 23, 2020 2:03
This is very cool!
November 23, 2020 3:31
Very cool indeed!! Does this apply for VB.NET also?
November 23, 2020 4:46
145MB Hello World app...
SSS
November 23, 2020 4:55
You dropped one of Steven's requirements:
from csharp myprog.cs
And 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#".
November 23, 2020 7:20
Cool. But why? Really, what's the point of this? What problem are we trying to solve here?
November 23, 2020 8:04
I've been looking for the same ability of building Xamarin apps entirely from the command line and without a Visual Studio installed, but that seems to be impossible. Does anyone know if there's such a possibility?
November 23, 2020 9:06
thanks for the explanation. I am happy to have received knowledge from you
November 23, 2020 10:25
@Igor
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
November 23, 2020 16:34
@SSS

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"
November 23, 2020 16:51
Interesting, but needs

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.
November 24, 2020 7:17
@Michael Rumpler

thank you, Michael!
November 24, 2020 9:33
I simply could not leave your website before suggesting that I extremely
loved the usual information a person provide to your visitors?

Is gonna be back often in order to inspect new posts
November 26, 2020 5:52
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#.
November 26, 2020 12:25
I really like .NET 5. It's big step forward. One file deployment is great!

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.