Guide: Generic Host Integration

The D20Tek.Spectre.Console.Extensions.Hosting package bridges Spectre.Console.Cli to the .NET Generic Host (Microsoft.Extensions.Hosting), so command types resolve from the host's service provider while Spectre-registered types still work.

Run a CommandApp from a host

Build a host, then create and run a CommandApp bridged to it:

using D20Tek.Spectre.Console.Extensions.Hosting;
using Microsoft.Extensions.Hosting;

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSingleton<IGreetingService, GreetingService>();
var host = builder.Build();

return await host.RunCommandAppAsync(args, config =>
{
	config.AddCommand<GreetCommand>("greet");
});

RunCommandAppAsync and RunCommandApp create the app, apply your command configuration, and run it, returning the exit code.

Use the fluent host builder

CreateCommandAppBuilder returns a HostCommandAppBuilder for a fluent flow:

return await host.CreateCommandAppBuilder()
	.WithDefaultCommand<DefaultCommand>()
	.ConfigureCommands(config => config.AddCommand<GreetCommand>("greet"))
	.Build()
	.RunAsync(args);

CreateCommandApp returns a configured CommandApp directly when you want to run it yourself.

Split startup with HostStartupBase

HostStartupBase separates host service registration from command configuration. Register it with WithStartup<TStartup> on the host application builder; ConfigureServices runs immediately (pre-build), and ConfigureCommands is applied automatically when the CommandApp is built (post-build):

public sealed class AppStartup : HostStartupBase
{
	public override void ConfigureServices(IServiceCollection services) =>
		services.AddSingleton<IGreetingService, GreetingService>();

	public override IConfigurator ConfigureCommands(IConfigurator config)
	{
		config.AddCommand<GreetCommand>("greet");
		return config;
	}
}

var builder = Host.CreateApplicationBuilder(args);
builder.WithStartup<AppStartup>();
var host = builder.Build();

return await host.RunCommandAppAsync(args, _ => { });

Runtime registrations captured from Spectre resolve through a composite provider, so a Spectre-registered type can depend on another Spectre-registered type while host services take precedence.

An unhandled error has occurred. Reload 🗙