Create a quick .NET Core CLI with System.CommandLine, Logging and Dependency Injection.
Writing a mature CLI on .NET Core doesn’t have to be difficult.
The other day, I had a requirement to create a simple command-line application to do some database housekeeping. I’m a bit of a perfectionist (hum hum) so to me, a simple CLI should have at least the following features:
- Robust argument parsing and validation
- Logging
- Testability
The last one, Testability, to me is almost synonymous with Dependency Injection. I love how DI helps to set things up in a modular fashion and therefore allows you to write proper, isolated Unit Tests for everything you do.
.NET Core comes with a very simple DI framework. While some say it isn’t “powerful enough” (whatever that means) I have found no reason to switch to another framework.
But before we dive into DI (which is going to make Logging trivial, as you’ll see) let’s tackle the first requirement: robust argument parsing and validation. For this, we turn to the (at the time of writing, experimental) System.CommandLine package.
Creating our CLI
I could write a few paragraphs on what System.CommandLine is and what it does but how about I just show you?
Let’s start with a basic console application. In any terminal (I can highly recommend the new Windows Terminal, if you’re on Windows), create a new project:
mkdir ohmy-cli
cd ohmy-cli
dotnet new console
This gets us a bog-standard .NET Core command-line application. It works, too! Just enter dotnet run
while in the root of your project and voilà:
It can even accept arguments. But it’s a long way from “robust argument parsing and validation”. Let’s change that.
First, add the System.CommandLine package:
dotnet add package System.CommandLine --prerelease
Notice the --prerelease
argument? That’s needed because System.CommandLine is still in beta.
Replace the Main
method and with the following code (I’ll explain below):