Method ConfigureCommandApp
- Namespace
- Ploch.CommandLine.Spectre
- Assembly
- Ploch.CommandLine.Spectre.dll
ConfigureCommandApp(Action<IConfigurator>)
Builds and configures the command-line application.
public ICommandAppExecutor ConfigureCommandApp(Action<IConfigurator> configurator)
Parameters
configuratorAction<IConfigurator>Command line application configurator used to configure the commands and options.
Returns
- ICommandAppExecutor
An instance of ICommandAppExecutor allowing execution of the app.
Remarks
The returned executor permits one execution attempt: an attempt may build the host behind it and Build() cannot be called again, so every attempt consumes the executor and a second Run(params IEnumerable<string>) or RunAsync(params IEnumerable<string>) on it throws InvalidOperationException. Call this method again to build a fresh executor for another run; it replays the same recorded configuration over the same cancellation source. Cancellation is permanent, so after an attempt that was cancelled - by Ctrl+C or through the registered CancellationTokenSource - this method throws InvalidOperationException rather than hand out an executor whose every command would start with an already-cancelled token. To run again after cancellation, start from a new builder (Create(params IEnumerable<string>)) or pass a fresh source to the constructor.
Unless ShowBanner(bool) was switched off, this call writes the start-up banner to standard error
— so it precedes Spectre's own help and version output too — and registers the
Spectre.Console.Cli.ICommandInterceptor that writes the "Executing command" line to standard error before each
command. That interceptor is registered first, before the services bundles and the caller's delegates,
so it runs before any interceptor the caller registers, through a bundle, ConfigureServices(Action<IServiceCollection>)
or Spectre's SetInterceptor. A default command is announced as "the default command".
Every ConfigureServices(Action<HostBuilderContext, IServiceCollection>),
ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder>) and
ConfigureHost(Action<IHostBuilder>) call is applied to the host builder in the order the calls were made, so the
fluent chain reads the way it executes. Of two service registrations for the same service, the one from the
later call wins, whether it was made through ConfigureServices or through
ConfigureServices(Action<HostBuilderContext, IServiceCollection>) inside a ConfigureHost(Action<IHostBuilder>) delegate. Likewise for
two application configuration sources supplying the same key, made through ConfigureAppConfiguration
or through ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder>) inside ConfigureHost(Action<IHostBuilder>).
Call order decides precedence between delegates of the same kind only. The host builder still runs its phases in its own fixed order, whatever order the calls were recorded in: host configuration (ConfigureHostConfiguration(Action<IConfigurationBuilder>)), then application configuration, then services, then ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder>). So an application configuration source always overrides a host configuration source for the same key, and a container delegate always runs after every service delegate.
The builder's own defaults sit outside that sequence. The default host configuration sources —
appsettings.json, appsettings.{Environment}.json, user secrets in Development, environment
variables and the command-line arguments, in ascending precedence — are added before any caller
application configuration source, and the registered services bundles are configured before any caller
service registration, so a caller can override both. The application's
CancellationTokenSource is registered after every caller service delegate, so no
ConfigureServices call can replace it; only a container delegate or a custom service provider
factory, which run later still, could. The token handed to running commands always comes from the
builder's own source, whatever the container holds.
The application exits with the codes ExitCode documents. A command line Spectre.Console.Cli
cannot parse or bind, and settings that fail validation, are reported by Spectre as before but exit with
InvalidInput rather than Spectre's own -1; an exception that escapes a
command not derived from AppCommand<TSettings> or AsyncAppCommand<TSettings>
goes to the registered IExceptionHandler, whose return value is the exit code; and a
failure before the host exists - one thrown while building it - is reported and exits with
Error. The handler that does this is set before configurator
runs, so a SetExceptionHandler or PropagateExceptions call in the delegate replaces it. Two
of Spectre's own early returns are unchanged: a branch invoked without a sub-command, and a default command
invoked without its required arguments, both show help and return 1.
The host is built once a run of the returned executor has parsed its arguments and resolves the
command — a parse failure or --version returns before any host exists — and it exists for
dependency injection, configuration and logging only: the library never starts it. A CLI command is
the unit of work, so StartAsync(CancellationToken) is not called, and an IHostedService
registered through ConfigureServices — with AddHostedService, for instance — has neither
its StartAsync(CancellationToken) nor its StopAsync(CancellationToken) invoked by
the library. A host that was built is disposed when the run ends. Starting the host around the command
is a possible 1.x feature, tracked as PLO-785.
Exceptions
- ArgumentNullException
Thrown when
configuratoris null.- ObjectDisposedException
Thrown when the builder has been disposed.
- InvalidOperationException
Thrown when the application info has no name, or when the builder's CancellationTokenSource has already been cancelled.