C# .NET Tools with System.CommandLine

Table of Contents

The System.CommandLine library is a powerful tool for building command-line applications in C# .NET. It provides a robust and flexible framework for creating command-line interfaces (CLIs) with ease. In this article, we will explore the various aspects of System.CommandLine, including its features, usage, and coding examples.

Introduction to System.CommandLine

System.CommandLine is an open-source library developed by the .NET Foundation. It simplifies the process of creating command-line interfaces for your C# applications, making it easy to handle command-line arguments, parse input, and execute commands.

Key Features of System.CommandLine:

  1. Parsing Command-Line Arguments: System.CommandLine simplifies the parsing of command-line arguments by providing a straightforward way to define and parse arguments and options.
  2. Command Hierarchy: You can create complex CLI applications with nested commands, allowing you to organize and structure your application’s functionality in a user-friendly way.
  3. Auto-Generated Help: System.CommandLine can automatically generate help and usage information for your commands and options, making your CLI user-friendly and self-documenting.
  4. Validation and Error Handling: The library provides built-in validation and error handling mechanisms, ensuring that users receive informative error messages when they misuse your CLI.
  5. Tab Completion: It supports tab completion for a more user-friendly CLI experience.
  6. Customization: System.CommandLine allows you to customize various aspects of your CLI, such as formatting, styles, and behavior, to match your application’s requirements.
  7. Cross-Platform: It is cross-platform and works seamlessly on Windows, macOS, and Linux.

Now, let’s dive into how you can use System.CommandLine in your C# .NET applications.

Setting up System.CommandLine

Before you start using System.CommandLine, you need to add it to your project. You can do this using NuGet Package Manager or by adding a reference in your project file.

dotnet add package System.CommandLine

Once you’ve added the library, you can start building your CLI application.

Defining Commands and Options

The foundation of any CLI application is defining commands and options. Commands represent the actions your application can perform, while options are used to modify the behavior of these commands.

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

class Program
{
    static int Main(string[] args)
    {
        var rootCommand = new RootCommand
        {
            new Option<int>("--number", "An integer argument"),
            new Option<string>("--name", "A string argument"),
        };

        rootCommand.Handler = CommandHandler.Create<int, string>((number, name) =>
        {
            Console.WriteLine($"Number: {number}");
            Console.WriteLine($"Name: {name}");
        });

        return rootCommand.Invoke(args);
    }
}

In this example, we define a RootCommand with two options, --number and --name. We also specify a Handler that will be executed when the command is invoked.

Parsing Command-Line Arguments

To parse command-line arguments, you can use the rootCommand.Invoke(args) method, where args is an array of strings representing the command-line arguments passed to your application.

For example, if you run the application with the following command:

dotnet myapp.dll --number 42 --name John

The Handler method will be called with the values 42 and John for the --number and --name options, respectively.

Creating Subcommands

Subcommands allow you to organize your CLI application into smaller, manageable pieces. Here’s an example of how to create a subcommand:

var mainCommand = new RootCommand
{
    new Command("greet")
    {
        new Option<string>("--name", "The name to greet"),
    },
};

mainCommand.Handler = CommandHandler.Create<string>((name) =>
{
    Console.WriteLine($"Hello, {name}!");
});

return mainCommand.Invoke(args);

With this setup, you can run your CLI like this:

dotnet myapp.dll greet --name Alice

This will display Hello, Alice! on the console.

Generating Auto-Generated Help

System.CommandLine can generate help documentation for your CLI application automatically. To enable this feature, you can use the --help option, which is automatically added by default. When the user runs dotnet myapp.dll --help, they will see a detailed description of the available commands and options.

Validation and Error Handling

System.CommandLine provides built-in validation and error handling mechanisms to ensure that users provide valid input. You can define validation rules for your options and commands, and the library will generate informative error messages for you.

Here’s an example of how to define validation for an option:

var option = new Option<int>("--number", "An integer argument")
{
    Argument = new Argument<int>((symbolResult) =>
    {
        if (!int.TryParse(symbolResult.Tokens.Single().Value, out int value) || value < 0)
        {
            throw new ArgumentException("The number must be a positive integer.");
        }
        return value;
    }),
};

In this example, we check if the value of the --number option is a positive integer. If not, an exception is thrown with a custom error message.

Customization and Styling

System.CommandLine allows you to customize various aspects of your CLI, including formatting, styles, and behavior. You can define custom help text, change the color scheme, and apply styles to your CLI application to make it unique and user-friendly.

Tab Completion

Tab completion is a valuable feature that enhances the usability of your CLI application. System.CommandLine supports tab completion out of the box, making it easy for users to discover available commands and options.

To enable tab completion, you need to integrate System.CommandLine with your shell. The library provides guidance on how to set up tab completion for various shells like bash, zsh, and PowerShell.

In the previous sections, we covered the basics of System.CommandLine for building C# .NET command-line applications. Now, let’s explore some advanced features and tips that will help you make the most of this library.

Handling Input and Output

System.CommandLine provides mechanisms for handling input and output streams, allowing your CLI application to read from and write to standard input, standard output, and standard error. You can use the StandardStreamWriter and StandardStreamReader classes for this purpose. Here’s an example of how to use them:

using System;
using System.CommandLine;
using System.CommandLine.IO;

class Program
{
    static int Main(string[] args)
    {
        var rootCommand = new RootCommand
        {
            new Argument<string>("--file", "A file path"),
        };

        rootCommand.Handler = CommandHandler.Create<IConsole, string>((console, file) =>
        {
            console.Out.WriteLine($"Reading from {file}");
            using (var reader = new StandardStreamReader(console.In))
            {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    console.Out.WriteLine($"Read: {line}");
                }
            }
        });

        return rootCommand.Invoke(args);
    }
}

In this example, we use IConsole to access the input and output streams, and we read lines from standard input and write them to standard output.

Prompting for User Input

Sometimes, you may need to prompt the user for input interactively. You can use libraries like System.CommandLine.Prompt to simplify this process. Here’s a basic example:

using System;
using System.CommandLine;
using System.CommandLine.Prompt;

class Program
{
    static int Main(string[] args)
    {
        var rootCommand = new RootCommand
        {
            new Command("ask")
            {
                Handler = CommandHandler.Create<IConsole>((console) =>
                {
                    var name = Prompt.GetString("Enter your name: ");
                    console.Out.WriteLine($"Hello, {name}!");
                })
            },
        };

        return rootCommand.Invoke(args);
    }
}

In this example, we use Prompt.GetString to interactively ask the user for their name and then print a greeting.

Cross-Platform Development

System.CommandLine is designed to work across various platforms, including Windows, macOS, and Linux. It ensures consistent behavior and experience for users, regardless of their operating system. When developing your CLI application, consider testing it on different platforms to ensure compatibility.

Adding Documentation and Help Text

Well-documented CLIs are user-friendly and provide a better experience for your users. You can add descriptions and help text to your commands and options to make your CLI self-explanatory. Here’s an example:

var option = new Option<int>("--number", "An integer argument")
{
    Description = "Specify an integer value.",
    Argument = new Argument<int>((symbolResult) =>
    {
        // Validation logic here
    }),
};

In this snippet, we added a description to the --number option, making it clear to users what it does.

Testing Your CLI

Testing is an essential part of developing CLI applications. You can use unit testing frameworks like MSTest, NUnit, or xUnit to test your command-line application’s functionality. Write test cases to cover various scenarios, including valid inputs, edge cases, and error handling.

Distributing Your CLI

Once you’ve developed and tested your CLI application, you can distribute it to users. Common distribution methods include creating standalone executables, distributing via NuGet, or publishing to package managers like Chocolatey or Homebrew.

Conclusion

System.CommandLine is a versatile library for building command-line applications in C# .NET. With its advanced features, customization options, and cross-platform compatibility, it empowers you to create robust and user-friendly CLI tools. Whether you’re building a simple utility or a complex command-line application, System.CommandLine is a valuable tool in your development arsenal. By following best practices and exploring the library’s advanced features, you can create CLI applications that meet the needs of your users effectively.

Command PATH Security in Go

Command PATH Security in Go

In the realm of software development, security is paramount. Whether you’re building a small utility or a large-scale application, ensuring that your code is robust

Read More »
Undefined vs Null in JavaScript

Undefined vs Null in JavaScript

JavaScript, as a dynamically-typed language, provides two distinct primitive values to represent the absence of a meaningful value: undefined and null. Although they might seem

Read More »