Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

RunInfoBuilder

4.00/5 (2 votes)
26 Oct 2018CPOL2 min read 4.3K  
.NET Command Line Parser, utilizing object trees for command configurations

Introduction

RunInfoBuilder (https://github.com/rushfive/RunInfoBuilder) is a Command Line Parser library that I've been developing for a while now.

What's different with this library, compared to many of the already existing parsers out there, is that it doesn't use Attributes to tell the parser how to handle program arguments. Instead, you tell the parser by passing it a command configuration object.

Using Attributes works okay for simple binding schemes (e.g., take this program argument and bind it to a property), but if you want to do anything more advanced, like define a custom callback for validations, Attributes begin to fall short.

A Simple Example

A program is desired that can read some message from the program arguments, and then do one of many things as determined by a command.

For example, it may take the message and send it off to some HTTP endpoint. Also, the user can optionally specify that the request should be retried on fail.

The required information for this has been collected into this RunInfo class:

C#
public class SendRequestRunInfo
{
    public string RequestUrl { get; set; }
    public string Message { get; set; }
    public int DelayMinutes { get; set; }
    public bool RetryOnFail { set; set; }
}

The program should take three program arguments and simply bind them to the properties. To do this, a Command called sendhttp is added to the CommandStore:

C#
// initialize a builder instance
var builder = new RunInfoBuilder();

// add the 'sendhttp' command to the store
builder.Commands.Add(new Command<sendrequestruninfo>
{
    Key = "sendhttp",
    Arguments =
    {
        new PropertyArgument<sendrequestruninfo, string="">
        {
            Property = ri => ri.RequestUrl
        },
        new PropertyArgument<sendrequestruninfo, string="">
        {
            Property = ri => ri.Message
        },
        new PropertyArgument<sendrequestruninfo, int="">
        {
            Property = ri => ri.DelayMinutes
        }
    },
    Options =
    {
        new Option<sendrequestruninfo, bool="">
        {
            Key = "retry | r",
            Property = ri => ri.RetryOnFail
        }
    }
});

// build the run info object by passing program arguments (led by the command's key)
var args = new string[] 
{ "sendhttp", "http://www.somewhere.com", "hello from program!", "3", "--retry" };
var runInfo = builder.Build(args);

The resulting runInfo variable will be of type SendRequestRunInfo with the expected values:

C#
{
    RequestUrl: 'http://www.somewhere.com',
    Message: 'hello from program!',
    DelayMinutes: 3,
    RetryOnFail: true
}

The values were parsed from the program arguments and bound to the RunInfo properties as configured. Also, the RetryOnFail property was set to true because the option was specified (`--retry`). The option could also have been specified by `-r` instead because a short key was configured for the option.

This is a very simple example, illustrating the most basic of binding requirements: simple 1-to-1 mappings of program arguments to properties.

There's a lot more that can be done and configured, but hopefully you can at least see how simple and expressive defining commands through an object is. You can take a quick look at any command configuration and immediately know how it parses the program arguments.

Core Features

The library handles several other Argument types such as sequences, mutually exclusive sets, etc.

Other core features include:

  • Options and SubCommands
  • Configurable Parser, handles most System types out of the box
  • Help Menu with clean defaults
  • Versioning
  • Hooks (for extensibility)

In Depth Documentation

If the example above has captured your interest, check out the README on the project's github page: https://github.com/rushfive/RunInfoBuilder

I'd love to hear your thoughts and ideas. Thanks for reading!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)