Command-line-api: CLI with Worker Service Example

Created on 14 Jun 2019  路  5Comments  路  Source: dotnet/command-line-api

Is there (or could one be created) an example how to use this API with the new Worker Service project type that is releasing with .NET Core v3?

Any feedback will be appreciated.

Most helpful comment

@shaggygi so using the AddHostedService method within ConfigureServices should work just fine.

public static partial class Program
{
    public static Task Main(string[] args)
    {
        var parser = new CommandLineBuilder(
            new RootCommand{
                Handler = CommandHandler.Create<IHost>(Run)
            })
            .UseDefaults()
            .UseHost(host =>
            {
                host.UseWindowsService();
                host.ConfigureServices(services =>
                {
                    services.AddHostedService<Worker>();
                });
            })
            .Build();

        return parser.InvokeAsync(args);
    }
}

In the example above, you'd do your service work within the Worker class instead of the handler, so you'd just write a handler that just waits for the host to shutdown like this:

public static partial class Program
{
    internal static Task Run(IHost host)
    {
        var services = host.Services;
        var lifetime = services.GetRequiredService<IHostApplicationLifetime>();
        return Task.Delay(Timeout.InfiniteTimeSpan, lifetime.ApplicationStopped);
    }
}

Note that in the example above I am using the Microsoft.Extensions.Hosting.WindowsServices package and the UseWindowsService extension method. This will override the lifetime used within the CommandLine invocation pipeline (i.e. InvocationLifetime).

If you want to examine the parse result from the command line invocation within your service, you can add ParseResult as a constructor argument to your Worker class. DI will automagically inject the parse result from the invocation.

All 5 comments

Take a look at the work being done by @couven92 and @tmds on System.CommandLine.Hosting. Worker services use the generic host so this should let you integrate them, though it's not something I've tried.

@shaggygi so using the AddHostedService method within ConfigureServices should work just fine.

public static partial class Program
{
    public static Task Main(string[] args)
    {
        var parser = new CommandLineBuilder(
            new RootCommand{
                Handler = CommandHandler.Create<IHost>(Run)
            })
            .UseDefaults()
            .UseHost(host =>
            {
                host.UseWindowsService();
                host.ConfigureServices(services =>
                {
                    services.AddHostedService<Worker>();
                });
            })
            .Build();

        return parser.InvokeAsync(args);
    }
}

In the example above, you'd do your service work within the Worker class instead of the handler, so you'd just write a handler that just waits for the host to shutdown like this:

public static partial class Program
{
    internal static Task Run(IHost host)
    {
        var services = host.Services;
        var lifetime = services.GetRequiredService<IHostApplicationLifetime>();
        return Task.Delay(Timeout.InfiniteTimeSpan, lifetime.ApplicationStopped);
    }
}

Note that in the example above I am using the Microsoft.Extensions.Hosting.WindowsServices package and the UseWindowsService extension method. This will override the lifetime used within the CommandLine invocation pipeline (i.e. InvocationLifetime).

If you want to examine the parse result from the command line invocation within your service, you can add ParseResult as a constructor argument to your Worker class. DI will automagically inject the parse result from the invocation.

@couven92 Thanks a bunch! This was helpful info.

@fredrikhr I've been trying to get access to the parse result/configured options inside of ConfigureServices so I can dynamically add dynamic workers based on parsed arguments (and register all workers with defaults if there is no parse result). Has this been considered? I haven't really found a good way to do this.

This question relates to the order of operations discussed in #1025.

Was this page helpful?
0 / 5 - 0 ratings