Skip to content

Writing Commands ​

JasperFx provides two base classes for building CLI commands.

Synchronous Commands ​

Extend JasperFxCommand<T> for commands that do not need async operations:

cs
[Description("Say hello to someone")]
public class GreetingCommand : JasperFxCommand<GreetingInput>
{
    public override bool Execute(GreetingInput input)
    {
        Console.WriteLine($"Hello, {input.Name}!");
        return true;
    }
}

snippet source | anchor

cs
[Description("Say hello to someone")]
public class GreetingCommand : JasperFxCommand<GreetingInput>
{
    public override bool Execute(GreetingInput input)
    {
        Console.WriteLine($"Hello, {input.Name}!");
        return true;
    }
}

snippet source | anchor

The Execute method returns true for success or false for failure. The exit code is set accordingly.

Async Commands ​

Extend JasperFxAsyncCommand<T> when you need to perform async work:

cs
[Description("Say hello to someone asynchronously")]
public class AsyncGreetingCommand : JasperFxAsyncCommand<GreetingInput>
{
    public override async Task<bool> Execute(GreetingInput input)
    {
        await Task.Delay(100);
        Console.WriteLine($"Hello, {input.Name}!");
        return true;
    }
}

snippet source | anchor

cs
[Description("Say hello to someone asynchronously")]
public class AsyncGreetingCommand : JasperFxAsyncCommand<GreetingInput>
{
    public override async Task<bool> Execute(GreetingInput input)
    {
        await Task.Delay(100);
        Console.WriteLine($"Hello, {input.Name}!");
        return true;
    }
}

snippet source | anchor

Input Classes ​

Every command takes an input class that defines its arguments and flags:

cs
public class GreetingInput
{
    [Description("The name to greet")]
    public string Name { get; set; } = "World";
}

snippet source | anchor

cs
public class GreetingInput
{
    [Description("The name to greet")]
    public string Name { get; set; } = "World";
}

snippet source | anchor

Properties on the input class are automatically mapped to command line arguments. See Arguments and Flags for the full attribute reference.

Command Naming ​

By default, the command name is derived from the class name by removing the Command suffix and converting to kebab-case. For example, GreetingCommand becomes greeting.

Usage Patterns ​

Commands can define multiple usage patterns similar to Git:

csharp
public class MyCommand : JasperFxCommand<MyInput>
{
    public MyCommand()
    {
        Usage("Default usage").Arguments(x => x.Name);
    }

    public override bool Execute(MyInput input) => true;
}

Next Steps ​

Released under the MIT License.