Skip to content

Defining custom directives

Adam Bajguz edited this page Apr 5, 2021 · 12 revisions

To define a custom directive, just create a new class that implements the IDirective or IPipelinedDirective interface and annotate it with [Directive] attribute:

[Directive(BuiltInDirectives.Debug, Description = "Starts a debugging mode. Application will wait for debugger to be attached before proceeding.")]
public sealed class DebugDirective : IPipelinedDirective
{
    /// <inheritdoc/>
    public ValueTask OnInitializedAsync(CancellationToken cancellationToken)
    {
        return default;
    }

    /// <inheritdoc/>
    public async ValueTask HandleAsync(ICliContext context, CommandPipelineHandlerDelegate next, CancellationToken cancellationToken)
    {
#if NET5_0
        int processId = Environment.ProcessId;
#else
        int processId = Process.GetCurrentProcess().Id;
#endif

        IConsole console = context.Console;

        console.Output.WithForegroundColor(ConsoleColor.Green, (output) => output.WriteLine($"Attach debugger to PID {processId} to continue."));

        Debugger.Launch();

        while (!Debugger.IsAttached)
            await Task.Delay(100, cancellationToken);

        await next();
    }
}

To facilitate both asynchronous and synchronous execution, OnInitializedAsync and HandleAsync methods return a ValueTask. In synchronous implementation, we can just put return default at the end, while in an asynchronous we can use the async/await keywords instead.

Similarly to commands, in every directive it is possible to define a description and a manual with [Directive] attribute. [Directive] attribute provides also an easy way for excluding a command from execution in normal mode through InteractiveModeOnly property.

Difference between IDirective and IPipelinedDirective

IDirective is a base interface for all directives, including IPipelinedDirective, and it contains a single method ValueTask OnInitializedAsync(CancellationToken cancellationToken) that can be used to initialize some data in the directive. Thus, directives implementing IDirective interface can be treated as simple directives that only purpose is to provide some extra data that can be accessed by every command in the application using ICliContext DI-injectable service.

Clone this wiki locally