Skip to content

Exceptions#

CommandDotNet rethrows all exceptions raised by the application code.

There are two patterns for handling exceptions

Register an ErrorHandler middleware method using MiddlewareSteps.ErrorHandler to ensure the middleware is one of the last in the pipeline to exit.

public static AppRunner GetRunner()
{
    return new AppRunner<Calculator>()
                .UseErrorHandler((ctx, ex) =>
                {
                    ctx.Console.Error.WriteLine(ex.Message);
                    return 1;
                });
                .Run(args);
}

Wrap the call to appRunner.Run(args) to handle global exceptions.

var appRunner = new AppRunner<Calculator>();
try
{
    return appRunner.Run(args);
}
catch(MyBusinessException ex)
{
    Console.Error.WriteLine(ex.Message);
}

Tip

Use the HandleErrorDeletage if you plan to test your app using the TestTools approach mentioned here

CommandDotNet internal errors are generally captured and return error code 1, using ExitCodes.Error.

Validation middleware will generally return error code 2, using ExitCodes.ValidationError.

Middlware should print error messages and return an error code instead of raising exceptions.

Additional Diagnostic Info#

CommandContext from the exception#

Exceptions that escape appRunner will contain the CommandContext in the Exception.Data property.

Use the ex.GetCommandContext() extension method to get the instance. Use the namespace CommandDotNet.Diagnostics

With the context, you can .PrintHelp() or ParserReport.Report to log details of the request.

Printing config information#

Configuration can be printed with appRunner.ToString(). See the Command Logger > AppConfig section for an example.

Alternatively, CommandLogger.Log(ctx) can be used to output CommandLogger for exception handling.

Full example#

var appRunner = new AppRunner<Calculator>();
try
{
    return appRunner.Run(args);
}
catch(MyBusinessException ex)
{
    Console.Error.WriteLine(ex.Message);

    var ctx = ex.GetCommandContext();

    // use CommandLogger if it has not already logged for this CommandContext
    if(!CommandLogger.HasLoggedFor(ctx))
    {
        CommandLogger.Log(
            ctx, 
            includeSystemInfo: true,
            includeAppConfig: true
        )
    }

    // print help for the target command
    // will be empty if the exception occurred before
    // a command could be parsed.
    Console.Out.WriteLine(ctx.PrintHelp());
}