Project Description

An easy to use and flexible command line argument handler, which helps to keep the inner structure of your console application clean. If you´ve struggled with other solutions caused by lack of support for dependency injection or expandability in general, this project is for you. The project is written in C# and is based on the .NET Framework 4.

The binaries of this project are available on the NuGet Gallery.

  PM> Install-Package ExtConsole

Quick Start

Using the commandline argument handler is quite easy. You can use the handler in any kind of application; could be a Windows Forms-, WPF- or an ordinary console application. First off you need a reference to the CommandLineHandler-assembly (if you need an assembly supporting the .NET Framework 2.0, you can simply compile your own release). The current commandline parser implementation does not support the standard UNIX notation for arguments, but you can simply extend or exchange the parser, if you don´t like the current notation. Before you start digging into customization of the parser, let me explain the idea behind the current implementation and how it works.

How to use the command line handler

As I wrote the handler expects arguments in a manner, which is different from the well-known UNIX-notation. Arguments (to be further known as option) must be prefixed with a "/" character. The handler allows to declare multiple names for an option, so there is no need for having a short- or long-name notation. Each option can have several parameters, which are prefixed with a "-" character. Both options and parameters can have a value (a value can be specified by using a colon). Okay, let´s have a look at some examples... Imagine a console application, which is working with a database and you want to specify the connection settings using commandline arguments: in the example below you see an option named "connection" followed by three parameters specifying the connection settings.

/connection -server:"local" -catalog:"master" -sspi:true

The next two snippets are showing how commandline arguments can be parsed using the handler.

class Program
{
  static void Main(string[] args)
  {
    var handler = new CommandLineHandler();
    var results = handler.Parse(args);
    ...
  }
}

If you need to handle commandline arguments somewhere else in the application, you can grab the arguments using the Environment.GetCommandLineArgs()-method.

class ViewModel
{
  public ViewModel()
  {
    var handler = new CommandLineHandler();
    var results = handler.Parse(Environment.GetCommandLineArgs());
    ...
  }
}

Okay, remember the sample commandline arguments shown before: The following example shows a console application consuming those arguments. As you can see, the handler allows you to write straightforward code - you don´t have to deal with additional classes and attributes to access the arguments.

using System;
using CommandLineHandler;

namespace Console1
{
  class Program
  {
    static void Main(string[] args)
    {
      var handler = new CommandLineHandler();

      var option = handler.Parse(args).FindByName("connection").First();

      var server = option.Parameter("server");
      var catalog = option.Parameter("catalog");
      var useIntegratedSecurity = (bool) option.Parameter("sspi");

      ...

    }
  }
}

Of course, it would be nice to map the commandline arguments to an object. Actually, the handler is doing that by default, but the objects are not strongly typed. In order to improve the mapping, we can simply derive a new type from the Option class (this is the generic baseclass which is used by the handler, if no mapping is declared). In the example below you can see the ConnectionInfo-class providing properties for the server-, catalog- and sspi-parameters. Instead of dealing with attributes you can use the Parameter-method in the property get accessors. You can instruct the Parameter-method to throw an exception, if the requested parameter is missing. At least, we have to register the ConnectionInfo-class to be used for the "connection" argument; this can be done using the Register-method of the CommandLineHandler-class. If you want to provide a short name for the option as well, you can simply register the same type with another name.

using System;
using CommandLineHandler;

namespace Console1
{
  class ConnectionInfo : Option
  {
    public string Server { get { return Parameter("server", true); } } // Note: Would throw a MissingOptionException, if the parameter is not specified.

    public string Catalog { get { return Parameter("catalog"); } }

    public bool UseIntegratedSecurity { get { return (bool) Parameter("sspi"); } }
  }

  class Program
  {
    static void Main(string[] args)
    {
      var handler = new CommandLineHandler();

      handler.Register<ConnectionInfo>("connection"); // Note: This connects the argument with a type.

      var connectionInfo = handler.Parse(args).Where((x) => x is ConnectionInfo).First<ConnectionInfo>();

      ...

    }
  }
}

Using Option- and OptionParameter-attributes

Attributes for option- and parameter-mapping are also supported. In the example below all the calls to the Parameter-method are removed, instead the OptionParameter-attribute is used. Please note the Option-attribute on the ConnectionInfo-class.

using System;
using CommandLineHandler;

namespace Console1
{
  [Option("connection")]
  [Option("c")] // Note: You can declare multiple names for an option.
  class ConnectionInfo : Option
  {
    [OptionParameter("server", Required = true)]
    public string Server { get; set; }

    [OptionParameter("catalog")]
    public string Catalog { get; set; }

    [OptionParameter("sspi")]
    [OptionParameter("useIntegratedSecurity")] // Note: You can declare multiple names for an option-parameter
    public bool UseIntegratedSecurity { get; set; }
  }

  class Program
  {
    static void Main(string[] args)
    {
      var handler = new CommandLineHandler();

      handler.Register<ConnectionInfo>(); // Note: The handler will reflect the option name from the attribute.

      var connectionInfo = handler.Parse(args).Where((x) => x is ConnectionInfo).First<ConnectionInfo>();

      ...

    }
  }
}

In some cases it might be a problem (or you just don´t like it) to derive a type from the Option class. The good news is, that you don´t have to use inheritance in order to get support for mapping. Of course, you will loose the possibility to cast objects returned by the Parse-method to a certain type. Instead, you have to create the instance by yourself and pass it to the MapObject-method of the associated mapper.

using System;
using CommandLineHandler;

namespace Console1
{
  class ConnectionInfo
  {
    [OptionParameter("server", Required = true)]
    public string Server { get; set; }

    ...
  }

  class Program
  {
    static void Main(string[] args)
    {
      var handler = new CommandLineHandler();

      var arg = handler.Parse(args).FindByName("connection").First();

      var connectionInfo = new ConnectionInfo();
      handler.Mapper.MapObject(arg, connectionInfo);
      ...

    }
  }
}

Last edited Aug 1, 2011 at 1:31 PM by mfriedrich, version 32