.NET Console App Tools

Part 1: ManyConsole

Recently, I was working with a developer who was putting the final touches on a command-line tool. I usually opt for a good Web-App and API, but it got me thinking about a pair of tools I've used to package up Windows console applications for use. ManyConsole makes command-line parameter creation and documentation easy and Fody abstracts a lot of MSBuild configuration to pack required dll files into one *.exe. Both tickle my fancy in the "get stuff done quickly and well" buttons. I'll cover Fody in the next post.

ManyConsole

Install-Package ManyConsole

Extending NDesk.Options, ManyConsole aims to speed up argument parsing in a manner that keeps the main method uncluttered.

ManyConsole provides a console interface for the user to list available commands, call and get help for each. - ManyConsole Quickstart Guide

Let's assume we want a command to run a ThingyService which will ostensibly print some results to some csv file.

We want to give the caller the option to override the default file name

We want to give the caller the option to add a timestamp to the filename

The first thing we'll do is build the command:

publicclassDoTheThingCommand:ConsoleCommand{// using dependency injection to resolveprivatereadonlyIThingyService_thingy;// set a default filename for some outputprivatestringFilename{get;set;}="ThingyReport.csv";// build the commandpublicDoTheThingCommand(IThingyServicethingy){_thingy=thingy;// define command line switch and descriptionIsCommand("csv","output csv report");HasLongDescription("outputs a CSV report for the thingy to the filesystem");// build optionsHasOption("f|filename:","specify filename",f=>Filename=f??Filename);HasOption("t|timestamp:","add timestamp to filename",t=>Filename=$"{Filename}-{DateTimeOffset.Now:yy-MM-dd}");}// define the behaviorpublicoverrideintRun(string[]remainingArguments){_thingy.DoIt(Filename);return1;}}

We'll add a little Dependency Injection:

publicstaticclassContainer{publicstaticIContainerBuild(){varbuilder=newContainerBuilder();// register the service implementationbuilder.RegisterType<ThingyService>().As<IThingyService>();// register all ManyConsole.ConsoleCommandsbuilder.RegisterAssemblyTypes(typeof(Program).Assembly).Where(x=>x.IsSubclassOf(typeof(ConsoleCommand))).As<ConsoleCommand>();returnbuilder.Build();}}