Minimal, good-citizen, C# console application boilerplate

Viewed 7120

What would be the minimal boilerplate code for a C# console application entry-point that would make it a well-behaved citizen?

When anyone goes out to create a Console Application project using Visual Studio (up to 2008 at the time of writing), you are presented with a boilerplate Program.cs that looks like this:

class Program
{
    static void Main(string[] args)
    {
    }
}

There are, however, a few things that everyone needs to do to make a console application a minimally good citizen. For example, if an exception occurs, then write out a clean message to standard error (Console.Error) and not standard output (Console.Out). Likewise, set the error code to a non-zero value in the event of some error so that calling processes can detect failures.

What would be the minimal boilerplate code for a C# console application entry-point that would make it a well-behaved citizen? What would you add or change to the following?

using System;
using System.Diagnostics;
using System.Linq;

static class Program
{
    static void Run(string[] args)
    {
        // TODO Replace line-echoing sample with actual application code

        string line;
        while ((line = Console.ReadLine()) != null)
            Console.WriteLine(line);
    }

    static int Main(string[] args)
    {
        // TODO Use a more robust arguments parser
        if (args.Any(arg => arg.Equals("/v") || arg.Equals("-v"))) // verbose?
            Trace.Listeners.Add(new ConsoleTraceListener(true));

        try
        {
            Run(args);
            return Environment.ExitCode;
        }
        catch (Exception e)
        {
            Console.Error.WriteLine(e.Message);
            Trace.TraceError(e.ToString());

            return Environment.ExitCode != 0
                 ? Environment.ExitCode : 100;
        }
    }
}

What this boilerplate achieves:

  • If an exception is thrown:
    • a clean message is printed to standard error
    • the full details are traced
    • the exit code is set to an arbitrary non-zero value (100) unless already set
  • Tracing can be turned on dynamically via a verbose switch
  • Tracing is sent to standard error to not interfere with the real output
  • On successful completion, the exit code reflects the last Environment.ExitCode value, which is usually zero but can be changed by downstream code
  • Program class is static

Non-goals of this question:

  • Identify command-line arguments handling code or library
  • Identify an external logging or tracing library
4 Answers
Related