blog
Ottorino Bruni  

Building a Powerful Console App in C# with .NET and System.CommandLine

Basic Handling of Command-Line Arguments in .NET Console Apps

Creating console applications often starts with handling command-line arguments. In .NET, this is done by parsing the args array provided to the Main method. This basic approach allows developers to capture user input and change the application’s behavior based on it. While this method works well for simple applications, it can become more difficult to manage as the number of parameters and complexity grow. In this section, we’ll look at the traditional way of handling command-line arguments, highlighting its simplicity and the challenges it can present as applications become more complex.

Before we proceed with our demonstration of the .NET Console application, it’s essential to clarify that this example is primarily designed to showcase the base functionalities. It may not be optimized or written in the most efficient manner.

Let’s consider a simple console application that takes a name and age as input and then outputs a message to the user. We’ll use the traditional approach of parsing the args array.

using System;

class Program
{
  static void Main(string[] args)
  {
    if (args.Length != 4)
    {
      Console.WriteLine("Usage: ConsoleApp --name <name> --age <age>");
      return;
    }

    string name = string.Empty;
    int age = 0;

    if (args[0] == "--name" && args[2] == "--age")
    {
      name = args[1];
      if (!int.TryParse(args[3], out age))
      {
         Console.WriteLine("Invalid age. Please provide a valid number.");
         return;
      }
    }
    else if (args[0] == "--age" && args[2] == "--name")
    {
      if (!int.TryParse(args[1], out age))
      {
        Console.WriteLine("Invalid age. Please provide a valid number.");
        return;
      }
      name = args[3];
    }
    else
    {
      Console.WriteLine("Usage: ConsoleApp --name <name> --age <age>");
      return;
    }

    if (name != null && age > 0)
    {
      Console.WriteLine($"Hello, {name}! You are {age} years old.");
    }
  }
}

What can I say? the code sucks and would not pass any code review but we only need examples. Eventually we can optimise it by maybe creating classes like Parser and Commander that check and execute the passed parameters correctly, but this takes time.

Building a Powerful Console App in C# with .NET and System.CommandLine

Explanation:

  1. Argument Count Check: The application first checks if exactly 4 arguments are provided. If not, it shows the usage instructions and exits.
  2. First Argument Check: The application then checks if the first argument is --name and the third argument is --age.
  3. Second Argument Check: If the first check is true, it assigns the values of name and age from the appropriate positions. If the age is not a valid integer, it shows an error message and exits.
  4. Alternative Argument Order: If the first argument is --age and the third argument is --name, it handles the arguments in this order as well.
  5. Invalid Argument Order: If neither condition is met, it shows the usage instructions.
  6. Output: If all conditions are met and the arguments are valid, it outputs the personalized greeting message.

Let’s try running our app:

dotnet run --name Otto --age 40
dotnet run --age 30 --name Marc
Hello, John! You are 30 years old.

This example demonstrates the traditional approach of handling command-line arguments in a .NET console application. As you can see, even with a small number of parameters, the code can quickly become cluttered and error-prone, highlighting the need for a more structured approach as complexity grows.

Simplify Command-Line App Development with System.CommandLine

System.CommandLine, maintained by Microsoft, is a powerful library designed to streamline the development of command-line applications. In its current preview beta, it offers essential functionality for parsing command-line input and generating help text, freeing developers from writing boilerplate code.

This section introduces System.CommandLine, emphasizing its role in simplifying app development by allowing developers to focus on writing application logic rather than parsing command-line arguments. Despite its prerelease status, the library is widely used, including by Microsoft’s .NET CLI and various other tools. With System.CommandLine, developers can create fast, lightweight, and AOT-capable CLI applications with ease, while benefitting from ongoing support and updates from Microsoft.

Run the following command:

dotnet add package System.CommandLine --prerelease
dotnet add package System.CommandLine.NamingConventionBinder --prerelease

Let’s get started and see how easy it is to convert our complex app with a few lines of code:

using System.CommandLine.Invocation;
using System.CommandLine.NamingConventionBinder;

class Program
{
  static int Main(string[] args)
  {
    var rootCommand = new RootCommand
    {
      new Option<string>("--name", "The name of the person to greet"),
      new Option<int>("--age", "The age of the person to greet")
    };

    rootCommand.Description = "Greets a person by name and age.";

    rootCommand.Handler = CommandHandler.Create<string, int>((name, age) =>
    {
      Console.WriteLine($"Hello, {name}! You are {age} years old.");
    });

    return rootCommand.Invoke(args);
  }
}
Building a Powerful Console App in C# with .NET and System.CommandLine

Explanation:

  1. Command Definition: We define a RootCommand object, which represents the main command of our application.
  2. Options: We add two options to the RootCommand: --name and --age, representing the name and age of the person to greet, respectively.
  3. Description: We set a description for the RootCommand to provide context for the application’s purpose.
  4. Handler: We define a command handler using CommandHandler.Create, specifying the types of arguments (string and int) that the handler expects. Inside the handler, we simply print a greeting message using the provided name and age.
  5. Invocation: We invoke the RootCommand with the provided command-line arguments using rootCommand.Invoke(args).

This approach significantly simplifies the code compared to manually parsing the args array. System.CommandLine takes care of parsing the command-line arguments and passing them to the handler, allowing us to focus on the application logic.

Building a Powerful Console App in C# with .NET and System.CommandLine

Simplifying User Interaction with Automated Help Generation

System.CommandLine’s automatic help generation is a significant advantage. In addition to simplifying command-line interface development, it offers the built-in functionality to generate comprehensive help messages. This feature not only saves time and effort in documenting commands and options but also ensures that users can quickly understand how to use your program without the need for external documentation.

This is an example of our program without entering the parameters:

Greets a person by name and age.

Usage:
ConsoleApp [options]

Options:
--name <name> The name of the person to greet
--age <age> The age of the person to greet
--version Show version information
-?, -h, --help Show help and usage information

Use "ConsoleApp [command] --help" for more information about a command.
Building a Powerful Console App in C# with .NET and System.CommandLine

Empowering Console Applications: Concluding Remarks

As I was looking for ways to improve my console applications, I came across the System.CommandLine library and was impressed by how easy it was to use. Handling parameters in console apps can be tricky, but System.CommandLine makes it simple with lots of useful features. Even though it’s still in beta, I didn’t hesitate to use it in my own projects and highly recommend it. Plus, knowing that it’s supported by Microsoft gives me confidence in its reliability. Are you thinking about giving it a try? I’d love to hear your thoughts!

If you think your friends or network would find this article useful, please consider sharing it with them. Your support is greatly appreciated.

Thanks for reading! ????

Leave A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.