---
title: "Create a plugin to register a command"
slug: "create-a-plugin-to-register-a-command"
abstract: "How to create a plugin to register a command, including how to create a project, create a plugin, create the command, and then register it."
---
# Create a plugin to register a command

You can use a [plugin](https://doc.sitecore.com/ch/en/developers/cloud-dev/plugins.html "Plugins") to register a command for use with the Content Hub CLI. In this example, you'll create a command called `echo` and then create a plugin to register it. The `echo` command outputs the string values that are passed in as arguments.

This walkthrough describes how to:

- [Create a project](https://doc.sitecore.com/ch/en/developers/cloud-dev/create-a-plugin-to-register-a-command.html#UUID-95841b04-1492-1ad6-f762-e3ba5b8a94ac_N1714069466870 "Create a project").
- [Create the plugin](https://doc.sitecore.com/ch/en/developers/cloud-dev/create-a-plugin-to-register-a-command.html#UUID-95841b04-1492-1ad6-f762-e3ba5b8a94ac_N1714069440317 "Create the plugin").
- [Create and register a command](https://doc.sitecore.com/ch/en/developers/cloud-dev/create-a-plugin-to-register-a-command.html#UUID-95841b04-1492-1ad6-f762-e3ba5b8a94ac_N1714069495645 "Create and register a command").

> [!note]
> The following examples use the .NET CLI, but you can achieve the same results in your preferred integrated development environment (IDE).

## Create a project

To create a project:

1. To create a class library, run the following commands:

    ```shell
    mkdir Walkthrough
    ```

    ```text
    cd Walkthrough
    ```

    ```text
    dotnet new classlib --framework net8.0
    ```

2. To add a reference to the core CLI functionality, run the following command :

    ```shell
    dotnet add package Sitecore.CH.Cli.Core --source https://nuget.sitecore.com/resources/v3/index.json
    ```

`Sitecore.CH.Cli.Core` provides access to the plugin infrastructure, useful utilities around file system access, configuration management, and console output. It also adds a dependency to the [Web Client SDK](https://doc.sitecore.com/ch/en/developers/cloud-dev/web-client-sdk.html "Web Client SDK").

## Create the plugin

While starting up the application, the CLI scans the plugin search paths for any types that inherit from `Sitecore.CH.Cli.Core.Abstractions.Infrastructure.IPlugin`.

To create the plugin:

- Rename the file `Class1.cs` to `Plugin.cs` and add the following code

    ```shell
    using Sitecore.CH.Cli.Core.Abstractions.Infrastructure;

    namespace Walkthrough
    {
      public class WalkthroughPlugin : IPlugin
      {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void RegisterCommands(ICommandRegistry registry)
        {
        }
      }
    }
    ```

This class contains the following methods:

- `ConfigureServices` - lets you register custom services in the shared service collection for dependency injection. Command handlers can resolve these services in their constructor. See [Dependency injection - .NET](https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection) for more information.
- `RegisterCommands` - registers new commands that are being delivered as part of this plugin, and makes them available through the CLI.

## Create and register a command

In this example, you create a command called `echo`. There are two methods you can use to do this:

- Use a separate command declaration and command handling. This is the preferred approach as it allows for better and easier unit testing of the command handler implementation.
- Specify options and command handling in the same class 

To create and register a command:

The value `echo` that is passed to the base constructor is the name under which the command will be made available later.

Arguments are passed into the function. `IHost` contains a reference to the service provider that resolves previously registered services. The value `echo` that is passed to the base constructor is the name under which the command will be made available later.

New commands can be added to existing groups, or to new groups created specifically for them. Several command groups are available as standard, including:

- `delivery` 
- `serialization` 
- `tenant` 
1. Create a file called `EchoCommand.cs` and add a separate command declaration and command handling as shown in the following code:

    ```csharp
    using System.CommandLine;
    using System.CommandLine.Invocation;
    using Sitecore.ContentHub.Cli.Shared.Abstractions.Commands;
    using Sitecore.ContentHub.Cli.Shared.Abstractions.Rendering;

    namespace Walkthrough;

    public class EchoCommand : BaseCommand <EchoCommandHandler>
    {
      public EchoCommand() : base("echo", "Echo a value")
      {
        // Options
        AddOption(new Option <string> (new[] {"--value", "-v"}, "Value to echo")
        {
          IsRequired = true
        });
      }
    }

    public class EchoCommandHandler : BaseCommandHandler
    {
      // Inject services from service provider
      public EchoCommandHandler(IOutputRenderer renderer) : base(renderer)
      {
      }

      public string Value { get; set; }

      // Command handling
      public override Task <int> InvokeDefaultAsync(InvocationContext context)
      {
        Renderer.WriteLine(Value);

        // Return exit code to indicate success or failure
        return Task.FromResult(0);
      }
    }
    ```

2. Or, use a separate class for arguments and options, as shown in the following code:

    ```shell
    using System;
    using System.CommandLine;
    using System.CommandLine.Invocation;
    using System.Threading.Tasks;
    using Microsoft.Extensions.Options;
    using Sitecore.CH.Cli.Core.Abstractions.Commands;
    using Sitecore.CH.Cli.Core.Abstractions.Rendering;
    using Stylelabs.M.Sdk.WebClient;

    namespace Walkthrough;

    public class EchoCommandParameters
    {
        public string Value { get; set; }
    }

    public class EchoCommand : BaseCommand<EchoCommandHandler>
    {
        public EchoCommand() : base("echo", "Echo a value")
        {
            // Options
            AddOption(new Option <string> (new[] {"--value", "-v"}, "Value to echo")
            {
                IsRequired = true
            });
        }
    }

    public class EchoCommandHandler : BaseCommandHandler
    {
        // Inject services from service provider
        public EchoCommandHandler(
            Lazy<IWebMClient> client,
            IOutputRenderer renderer,
            IOptions<EchoCommandParameters> parameters) : base(client, renderer)
        {
            Parameters = parameters.Value;
        }

        public EchoCommandParameters Parameters { get; }

        // Command handling
        public override Task<int> InvokeAsync(InvocationContext context)
        {
            Renderer.WriteLine(Parameters.Value);

            // Return exit code to indicate success or failure
            return Task.FromResult(0);
        }
    }
   
    ```

3. Specify options and command handling in the same class, as shown in the following code:

    ```shell
    using System.CommandLine;
      using System.CommandLine.NamingConventionBinder;
      using Microsoft.Extensions.DependencyInjection;
      using Microsoft.Extensions.Hosting;
      using Sitecore.ContentHub.Cli.Shared.Abstractions.Commands;
      using Sitecore.ContentHub.Cli.Shared.Abstractions.Rendering;

      namespace Walkthrough
      {
          public class EchoCommand : BaseCommand
        {
          public EchoCommand() : base("echo", "Echo a value")
          {
            // Options
            AddOption(new Option <string> (new[] {"--value", "-v"}, "Value to echo")
            {
              IsRequired = true
            });

            Handler = CommandHandler.Create <string>, IHost ((value, host) =
            {
              host.Services.GetService <IOutputRenderer> ().WriteLine(value);
            });
        }
      }
    ```

4. To connect the plugin class and the command, modify the `Plugin.cs` file updating the `RegisterCommands` method as follows:

    ```shell
    public class WalkthroughPlugin : IPlugin
    {
      ...

      public void RegisterCommands(ICommandRegistry registry)
      {
        // register the command to an existing command group
        registry.RegisterCommand("walkthrough", new EchoCommand());

        // register a new command group and its commands
        registry.RegisterCommandGroup(
          "walkthrough", new List <Command> { new EchoCommand() }, "Walkthrough plugin for demonstration purposes only");
      }

      ...
    }
    ```

After they are compiled and copied to a [discoverable plugin search path](https://doc.sitecore.com/ch/en/developers/cloud-dev/plugins.html "Plugins"), the `walkthrough` command group and `echo` command are included in the CLI. You can now run several commands to verify that everything has been set up correctly.

The following command starts from the `walkthrough` command group and verifies that the new `echo` command has been added:

```shell
ch-cli walkthrough --help

```

You can run the `echo` command as follows:

```shell
ch-cli walkthrough echo --value Hello

```