Required command was not provided on `RootCommand`
I am get error Required command was not provided. when running MyApp.exe --as-service with the following code below.
internal sealed class DefaultRootCommand : RootCommand
{
public DefaultRootCommand() : base("Description")
{
var exportCommand = new ExportCommand();
AddCommand(exportCommand);
AddOption(new Option<bool>("--as-service", "Option1"));
}
// ........
}
However if I remove the code below it works fine.
var exportCommand = new ExportCommand();
AddCommand(exportCommand);
Program.cs
static async Task<int> Main(string[] args)
{
var rootCommand = new DefaultRootCommand();
var parser = new CommandLineBuilder(rootCommand)
.UseHost(_ => new HostBuilder(), builder =>
{
builder.ConfigureDefaults(args);
builder.UseSystemd();
builder.UseWindowsService();
builder.UseCommandHandler<DefaultRootCommand, DefaultRootCommand.Handler>();
builder.UseCommandHandler<ExportCommand, ExportCommand.Handler>();
})
.UseDefaults()
.UseExceptionHandler(NullExceptionFilter.Handler)
.Build();
return await parser.InvokeAsync(args);
}
In 2.0.0-beta4.22272.1, the "Required command was not provided" error is set by ParseResultVisitor.ValidateCommandHandler if the user-specified command does not have a handler but has subcommands. This is called during Parser.Parse. Your code above calls builder.UseCommandHandler<DefaultRootCommand, DefaultRootCommand.Handler>() but I think this is executed too late and the parser has already made its decision. Perhaps you could work around this by assigning a dummy handler to the command initially, just to satisfy the parser; the hosting middleware would then substitute the correct handler after parsing finishes, so the dummy handler would never be called.
@elgonzo, the constructor is public RootCommand(string description = "").
In 2.0.0-beta4.22272.1, the "Required command was not provided" error is set by ParseResultVisitor.ValidateCommandHandler if the user-specified command does not have a handler but has subcommands. This is called during Parser.Parse. Your code above calls
builder.UseCommandHandler<DefaultRootCommand, DefaultRootCommand.Handler>()but I think this is executed too late and the parser has already made its decision. Perhaps you could work around this by assigning a dummy handler to the command initially, just to satisfy the parser; the hosting middleware would then substitute the correct handler after parsing finishes, so the dummy handler would never be called.
The workaround I found is create sub command and keep RootCommand handler empty like you said.
builder.UseCommandHandler<DefaultRootCommand, ICommandHandler>();
No, I meant you'd assign a dummy handler to the root command without UseCommandHandler, then let UseCommandHandler replace it with the real handler after parsing has finished.
No, I meant you'd assign a dummy handler to the root command without
UseCommandHandler, then letUseCommandHandlerreplace it with the real handler after parsing has finished.
But how would i do that if I was doing this for example:
internal sealed partial class DefaultRootCommand : RootCommand
{
public DefaultRootCommand() : base("Description")
{
var openWalletCommand = new OpenWalletCommand();
var startOption = new Option<bool>("--as-service", "Option1");
AddCommand(openWalletCommand);
AddOption(startOption);
}
public new sealed class Handler : ICommandHandler
{
public int Invoke(InvocationContext context)
{
// TODO: Add Code
}
public Task<int> InvokeAsync(InvocationContext context)
{
// TODO: Add Code
}
}
}
By assigning Command.Handler or calling some overload of Handler.SetHandler. For example, this.SetHandler((InvocationContext _) => {});.