public class MyCommand : Command
{
public MyCommand()
: base(name: "command", "sample command")
{
ConfigureArguments();
ConfigureOptions();
}
private void ConfigureArguments()
{
var sourceFileArg = new Argument<FileInfo>(name: "sourceFile", description: "File to use");
sourceFileArg.AddValidator(result => {
var parsedValue = result.GetValueForArgument(sourceFileArg);
if (!parsedValue.Exists)
{
result.ErrorMessage = $"File provided for '{sourceFileArg.Name}' not found at {parsedValue.FullName}";
}
});
AddArgument(sourceFileArg);
}
/// <summary>
/// Options are bound to handler properties by convention, from the longest alias name
/// </summary>
private void ConfigureOptions()
{
var stringOption = new Option<string?>(aliases: ["-o", "--option-string"], description: "A string option") {
IsRequired = false
};
stringOption.SetDefaultValue(Defaults.StringOption);
AddOption(stringOption);
}
private static class Defaults
{
public const string StringOption = "mystring";
}
/// <summary>
/// Handler public properties are bound by convention with argument and option names
/// </summary>
public new class Handler(ILogger<Handler> logger) : ICommandHandler
{
public required string OptionString { get; set; }
public required FileInfo SourceFile { get; set; }
public int Invoke(InvocationContext context)
{
throw new NotImplementedException();
}
public async Task<int> InvokeAsync(InvocationContext context)
{
logger.LogInformation("beginning streaming..");
try
{
var token = context.GetCancellationToken();
while (!token.IsCancellationRequested)
{
await BeginStreamingFile(token);
return 0;
}
}
catch (OperationCanceledException)
{
Console.WriteLine("User cancelled");
return -1;
}
return -1;
}
private async Task BeginStreamingFile(CancellationToken ct)
{
await using var sourceFileStream = new FileStream(SourceFile.FullName,
new FileStreamOptions {
Access = FileAccess.Read,
BufferSize = 0,
Mode = FileMode.Open,
Share = FileShare.Read,
Options = FileOptions.RandomAccess
});
await using var streamer = new SomeStreamerInstance();
streamer.OnProgress += (_, args) => {
// show progress to console
};
await streamer.Start(sourceFileStream, ct);
}
}
}
Any help is much appreciated.
Edit:
I've already seen that CommandLineBuilder.UseDefaults() also calls .CancelOnProcessTermination() that performs some event callback registration for ConsoleCancelEventHandler.
I just have no idea how exactly am I supposed to "correctly" write an ICommandler.InvokeAsync.
Hi.
I'm having issues with handling of user termination with current nuget packages:
Ctrl+C doesn't terminate async handler invocations. I believe I'm correctly propagating the cancellation token, but I guess I'm missing something.
Program.cs
MyCommand.cs
Any help is much appreciated.
Edit:
I've already seen that
CommandLineBuilder.UseDefaults()
also calls.CancelOnProcessTermination()
that performs some event callback registration for ConsoleCancelEventHandler.I just have no idea how exactly am I supposed to "correctly" write an
ICommandler.InvokeAsync
.