My preferred .NET console stack
devlead.se
devlead.se
With the advent of Blazor, you could also look at building rich UX on top of the very same business services used in the console variant. I have found that Blazor is productive enough to consider using universally for management/configuration/admin dashboards for whatever business process. You could even have console interface and multiple Blazor apps operating side-by-side within the same logical process. Microsoft's DI & AspNetCore support this kind of thing out of the box.
Silverlight required add-ons for all platforms to be pre-installed. That was too similar to Flash and Silvelight became obsolete as soon as these plug-ins were not going to be supported on iPad and iPhones. There was no real point anymore.
At this stage, I see Blazor as a necessity for the .Net platform to move forward on being relevant for apps that require UI. There is no real official .Net cross-platform way of building complex user interfaces.
Blazor has the advantage of being a platform on which MS can build on to bring all types of apps together: they can be OS agnostic (.NET 5.0 already runs on Win, Mac and Linux) and target web, desktop and mobile in one swoop, although it will require a few iterations to have an ecosystem rich and stable enough to work well and consistently everywhere.
Client-side Blazor can also be prerendered now and has much better trimming so you can still see static HTML content instantly while the rest loads up in the background.
I don't see a whole lot of developers familiar with this package but it is great if you can see yourself using PowerShell or a batch file wrapped to invoke it. No boilerplate, no parsing, auto generated help and type safe validations.
Reflection is common.
Back at Google, I really like how this was solved. Bazel (blaze) internally when doing java or python tool - would actually compile the java runner to become the main app, then the .jar (combined) could be part of it (not sure right now, but it could be), and any native C/C++ JVM code would be part of the java runner (all statically linked) - so you end up with single executable.
Same for python - any C/C++ linked externally becomes part of the "python.exe" (sorry, I'm mostly on windows terms now) + the rest of the compiled .python code - may go as .zip with the .exe - or even directly embedded as some data.
I really hope Microsoft goes this way. Distributing single (ok, two with .pdb) executables goes a long way of easing the process - CI, tools, or just here is a tool (to a coworker) that would work for you, and right now is... oh, and you need these extra .dlls (and app.config, and now .dll.recipe files, and who knows what else).
I do really wish .NET comes to realize that single true binary is a must (without temp files extracting, this is so prone to errors, security issues, leaks, etc.)
It looks like this Spectre.Console you are using is a bit more fancy albeit a lot newer.
Aside: I was testing the start-up time of my program last night and discovered that it is being delayed approx. 100ms by Spectre.Console. If any contributors are on this thread, it may be worth looking at start-up performance.
Making software should not be about making the life of the developer as easy as possible, it should be about making things easy, small, and FAST for the user.
What are you talking about? It's 1.4MB.
This is the easiest thing in the world to verify:
$ dotnet publish -c Release
Microsoft (R) Build Engine version 16.8.3+39993bd9d for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
ConsoleApp -> /tmp/ConsoleApp/bin/Release/net5.0/ConsoleApp.dll
ConsoleApp -> /tmp/ConsoleApp/bin/Release/net5.0/publish/
$ cd /tmp/ConsoleApp/bin/Release/net5.0/publish/
$ du -h
1.4M .
And no, I don't want to hear about any figures for self-contained builds. It's an article about useful packages to help architecture your .NET console app. It's to be read in that context, where the .NET 5 runtime is available.Then what is your point? When talking about the size required for a program to run, you have to weigh all of its dependencies.
For anyone interested, such a binary ends up at least 50MB, if we include the dependencies mentioned in the article in question.
.. if you don't make any use of assembly optimisation/trimming, sure.
$ dotnet publish -c Release
Microsoft (R) Build Engine version 16.8.3+39993bd9d for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
Restored /tmp/ConsoleApp/ConsoleApp.csproj (in 18.97 sec).
ConsoleApp -> /tmp/ConsoleApp/bin/Release/net5.0/linux-x64/ConsoleApp.dll
Optimizing assemblies for size, which may change the behavior of the app. Be sure to test after publishing. See: https://aka.ms/dotnet-illink
ConsoleApp -> /tmp/ConsoleApp/bin/Release/net5.0/linux-x64/publish/
$ cd /tmp/ConsoleApp/bin/Release/net5.0/linux-x64/publish/
$ ls
total 29M
> When talking about the size required for a program to run, you have to weigh all of its dependencies.Except the dependencies might not even be relevant depending on which OS you're targeting - and in the context of this article, why is this even interesting? You can make all of the same criticisms of the JVM, or .NET web apps or anything else - do you statically link libc?
Most people just install .NET on their machines. If so, that 1.4mb executable will run just fine.
And to what extreme do you take that line of thought? Should the kernel size be included?
You write:
>And you end up with a console app that is 20-100MB.
Yea, but you can also say
>And you end up with a decent size app that is 20-100MB.
and also you can say
>And you end up with a decent size app that is 2MB
because you already have runtime, because you use .NET apps.
Unless you are only doing Windows tooling, you probably do need to bear that in mind.
EDIT: That said, I do wish that the trimming/tree-shaking systems could do more to get the size and speed of easy-to-code solutions way down.
You're kidding yourself if you think the average person looks at the size of an app.
That depends on the target audience. IME the target audience of console/CLI programs are more likely to care about size. CLI apps tend to cater more to power users. And many users do definitely care about resource usage, and smaller size apps do in fact tend to use less resources.
All users definitely care about performance. A fast app feels nicer. Smaller-sized software tends to be faster. Weird correlation? I think not.
I think what made me defensive was the implication that these CLI libraries can be easily replaced with some small hand-coded solution. This particular library adds color coding, a structured help message based on the configuration, and some building blocks for DI, etc. Getting that stuff right in a hand-coded solution that isn't thousands of lines would take most developers a lot more time and effort.
If that was your takeaway from what I wrote that was definitely not my intention. I do not think that.
I am sure several of these libraries are well-crafted, the developer(s) behind them might be excellent and have cared a great deal about performance and did their best to optimize every function. My point was more: people tend to pull in a lot more functionality/features than they need, and the few things you do need, it is often better to write yourself (you may disagree again).
This will often give you the most optimized solution, and the one with the smallest binary.
In another HN thread, someone mentioned Unity and the size of the binary required just to display a pixel, a square, or whatever their example was--although their example was not an apple-for-apple comparison and not quite fair, the point still stands, that Unity is a general solution, and if your only requirement is drawing a pixel, of course Unity is not the correct solution.
However, I care even more about having apps/tools that help me achieve the desired goals, in an easy, clear, and elegant way.
If having bigger apps means that developers have more time to implement or improve features, and solve bugs, I'm all for it.
Contrast this with a game like Detroit.. It took my system(5700 XT and 3950x) what seemed like nearly 30 minutes to arrive at the menu screen due to having to compile all the shaders and who knows what else. I'm sure there were other considerations there, but still..
FWIW, this is sort of a legacy of .NET's "enterprisey" history. Code size and trimming wasn't really a priority when most .NET code ran server-side or inside enterprises, now it is.
There's been a lot of work happening recently to trim .NET executables and publish them as single files, and it looks like .NET binary sizes will eventually be in the same ballpark as Go: https://blog.kalalau-cantrell.com/2021/01/make-smaller-conso...
I think maybe in 2016? 2018? they were committing a lot to it, probably hoping to make it production ready. Then priorities shifted and they barely advanced and now they moved it into "runtimelab" which doesn't bode well to me.
you do not need CoreRT for trimming. but trimming is already there: https://devblogs.microsoft.com/dotnet/app-trimming-in-net-5/
it's still a long way to go, tough.
"Early adopters can experiment with native AOT form factor" is a priority-zero (highest priority) epic for .NET 6: https://github.com/dotnet/runtimelab/issues/248
Not the lowest rung on the ladder.
So is this type of boilerplate.
In software, the best software is one that was built and works to solve a problem, not necessarily one that is engineered perfectly.
Otherwise slack, chrome, etc... wouldn’t routinely eat up 1GB of ram just to open.
They do, they are well liked.
I know I’m grossly exaggerating, but the fast movement and the lack of ease of use has been one of the primary reasons to see us slowly move toward python and powershell after nearly two decades of C#. Being a windows happy enterprise org, we still make plenty of use of the .Net family and friends of course, but not really for development.
But lets not create this false narrative that somehow .NET has become super complex. Anyone can create a console application with -
dotnet new console -n TestConsoleApp
Python has an argument parser in the standard library
argparse - or close to it :-)
Net tooling used to be horror. Now its good. Speaking as someone who does CI/CD work on it for a long time. You seem to speak as someone who doesn't have .net muscle memory.
Programming is complex, unless you finish with hello world (even hello world is complex in enterprise environments).
As someone who has had to set up MSBuild & other BS for a CI server, I definitely agree with you.
For a dev used to double click Visual Studio, the current setups are more complex.
If 'it works on my computer' is a measure, then pre dot.net core era is as good as it can get.
Even pythons virtual environments take less time to use than .NET.
Sure I actually liked the "double click" thing in Visual Studio, but that had nothing to do with "if it works on my computer", it simply saved bundles of time because we'd publish every project to the same damn IIS instance and not have them all run their independant web-servers with their independant setups.
Hell we still put things behind the same damn IIS instance and it's load balancer and all that, because why wouldn't we? We're not Netflix, we don't need to scale to two billion people. Our max load is 50.000 concurrent users, yet our build load and our deployment pipeline is now so best-practice, SOLIDVOLID, Buzzworded, CONSOLELIEK and complicated might actually work for Netflix with enough iron.
What's worse is that, it's now your job. Not the operations dude who actually specialize in this, no yours, along with keeping up with you know, actual programming.
Being the public sector, we benchmark everything, and the things we don't benchmark we hire E&Y to benchmark, and you know what our most expensive resource has seen the biggest increase of their time going into over the past 30 years? Configuring and maintaining their tooling. Not developing new things that are useful for our actual business, no sir, but working with the tools that allow them to develop things. It's up by 130% compared to 1998.
I'm not sure what you'd call that inside big-tech, but in non-tech, we tend to call that, a waste of resources.
At least we can lower the cost by vendor-lock-in with azure, right?
> I know I’m grossly exaggerating...
I do not even think it is an exaggeration. Even the non-performant Python still feels like a hacker's, get-shit-done language compared to .Net. Anything .Net still feels like slow, enterprise bloat. Even "dotnet build/run" is slow, no matter size of your project.
Seems a bit presumptive to decide the requirements for every console app ever made. Shouldn't it be determined on a case-by-case basis whether a 20mb difference in app size matters?
Also, why exactly does a 20mb app size mean an app is too slow? I'm not really following that line of logic.
The title of the post is "My preferred .NET console stack", not "this is how every console app should be written."
To be honest, I don't think the typical use case for a template like this is to "Make software", it's to solve a problem as quickly and cheaply as possible. Building software to solve these types of problems is 99% about solving the problem and 1% about how well it performs.
I think you’re vastly optimistic about the ratio of ESR-“real-hacker” to “I just work here” developers, as well as the amount an end user cares if the executable is a 100kb vs 100 megs.
Dependencies, dependencies, dependencies = Reuse, modularisation, standardisation of boilerplate
If that would be true people would be using IRC, not Slack or Teams. Users don't care and your statement is completely false.
If you created two Telegram alternatives, that was identical except for performance, would users not choose to use the most performant one?
Statistics like these (I just found at random, but there are many like it available) demonstrates that your average user do in fact care a lot about performance:
https://www.marketingdive.com/news/google-53-of-mobile-users...
If I wrote the perfect chat app tomorrow, I'm talking universally loved by anyone who uses it. I'm not guaranteed to succeed. If someones whole family is on iMessage and they are happy they aren't going to be able to get them to switch. So they couldn't use my app if they wanted too.
Thus they stay with the "inferior" product. Average people aren't interested in the latest greatest. They just want it to work and as long as it does, they don't care about shortcomings that don't affect them. IE app size, speed(as long as its good enough)
I'm being sarcastic :-)
It provides simple decorator to turn functions into commands, sub-commands, etc, with easy options and built-in help.
Usually if you want structured information from some process then you just build a web application that does its work on a schedule or when it receives an API request. Console applications are great for "fire and forget" or even being called by something else and then passing pack simple data back to the caller if necessary.
I had a co-worker that built an extremely complex table display system using ncurses. I wondered what the point was - who is going to see all of these fancy tables? The person who SSH into the system and quickly validates its correctness and then closes the connection? Or people that use VNC/Remote Desktop just to see the status of what's going on?
Edit: referring to the functionality of Spectre.Console.
I frequently SSH into systems that are not running desktop environments and being able to run htop, iftop, tmux, or any "graphical" CLI application makes my time there much more pleasant.
Yes there is a need to have structured, interactive, non-text based interfaces in a CLI.
It depends on what you mean by "practically nothing". If you're going to deliver a non-trivial commandline application to do something useful for other people, it needs to have robust input validation, proper auto-complete and help that's sensitive to what command subcommand/option you're trying to invoke. Would also be nice to also get an --update option more or less "out of the box"(+).
Those things add up!
(+) With .net 5, I now see that clickonce allows you to publish a console app from visual studio, but it doesn't seem to work the way one one would expect. The console app is launched from a start-menu application ref, just like a wpf app. I would have liked it to add the command to the user's path so they could just use once they installed it.
It was hundreds of lines long, didn't work properly, and once I'd culled the crap, pointless, boilerplate was a whole 20 lines.
C# really is great, you can write a lot with some really clear, obvious, terse code. But the awful, over-engineered, useless code that seemingly 75% of C# developers write is not, it's unreadable crap that adds nothing to performance, massively hinders readability and tarnishes the language.
I've always used the (rather dated) library NDesk.Options [0]. Even though it was written way back in the .net 2 days. For me, it seems to hit a very nice sweet spot between power and complexity.
I think now folks have gotten used to auto-complete in powershell commands. It's really harsh to not give that to them when they're expecting it. :-)
I have yet to find a good way to avoid boilerplate in handling command line input on my console applications.
My naïve self feels that it should be standard, and yet every console application operates with different nuances. It's also a part of code that I see a disproportionate amount of bugs/feedback on (for sufficiently complicated programs). I see developers consistently underestimate the work required on handling command-line input.
I don't think this guys solution is a silver bullet but I'm happy to see the methods.
It's a bit heavy, I'd have to invest some time learning his framework but could be worth it. I've certainly written lots of command line parsing and logging code I'm not proud of.
b) There are certain things that look simple, but you _do not_ want to waste your time coding the corner cases yourself when this is a solved problem.
e.g. You might think that commandline args is simple, but it is very much not. if you '-file foo.txt' working, how will you handle '-file "C:\Program Files (x86)\bar\foo bar.txt" ' ?
If you get `-message hello` ? working, will your code handle `-message "hello, "friend""` ?
Having this prebuilt is useful.
(Yes, Windows is complicated by having two different built-in parsers for argv [CRT and shellapi] because the kernel itself doesn't have a concept of argv. But if we're talking about .Net programs then the runtime makes that choice and gives your entrypoint an argv, so again quote-evaluation is not in the program's purview.)
I'm less familiar with the library that OP is using, but it seems to be here: https://github.com/spectresystems/spectre.console/blob/main/...
Going in the other direction, generating command lines: https://github.com/natemcmaster/CommandLineUtils/blob/main/s...
I don't recommend re-inventing this
If you were writing a "production-level" console app with multiple commands, logging, needed DI, input validation, nice looking progress bars, etc. Then this is pretty much what I'd want for a console template tbh.
Spectre.Console looks insanely nice.
can we please please please stop making programming languages like this
public Thing _thing = new(); var thing = new Thing();
Thing thing = new();:) Really though this is just the old way to write C#. Even Java is starting to update this pattern.