Open voltagex opened 1 year ago
Whoops! This works a lot better when I pass MyCommand
into the builder itself!
new CommandLineBuilder(new MyCommand());
Will keep this open and see if I can get a complete example working.
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.CommandLine;
using System.CommandLine.Builder;
using System.CommandLine.Hosting;
using System.CommandLine.Invocation;
using System.CommandLine.Parsing;
namespace Test2
{
internal class Program
{
static void Main(string[] args)
{
var parser = new CommandLineBuilder(new MyCommand())
.UseHost(host =>
{
host.ConfigureServices(services =>
{
services.AddSingleton<IGreetingService, HelloService>();
services.AddSingleton<IFarewellService, FarewellService>();
services.Configure<FarewellOptions>(f => f.CustomFarewell = "Until we meet again");
})
.UseCommandHandler<MyCommand, MyCommandHandler>();
})
.Build();
var parseResult = parser.Parse(args);
var invokeResult = parser.Invoke(args);
}
}
public class MyCommandHandler : ICommandHandler
{
private readonly IGreetingService _greetingService;
private readonly IFarewellService _farewellService;
private readonly IOptions<FarewellOptions> _options;
public MyCommandHandler(IGreetingService greetingService, IFarewellService farewellService, IOptions<FarewellOptions>? farewellOptions)
{
_greetingService = greetingService;
_farewellService = farewellService;
_options = farewellOptions;
}
public int Invoke(InvocationContext context)
{
throw new NotImplementedException();
}
public Task<int> InvokeAsync(InvocationContext context)
{
Console.WriteLine(_greetingService.Greet());
Console.WriteLine(_farewellService.Farewell());
return Task.FromResult(0);
}
}
internal class MyCommand : RootCommand
{
public MyCommand() : base("")
{
var farewellOption = new Option<string>("--farewell");
this.AddOption(farewellOption);
}
}
public class FarewellOptions
{
public string CustomFarewell { get; set; }
}
public interface IGreetingService
{
string Greet();
}
public interface IFarewellService
{
string Farewell();
}
public class HelloService : IGreetingService
{
public HelloService()
{
}
public string Greet()
{
return "Hello!";
}
}
public class FarewellService : IFarewellService
{
private IOptions<FarewellOptions> _options;
public FarewellService(IOptions<FarewellOptions> options)
{
_options = options;
}
public string Farewell()
{
if (!string.IsNullOrEmpty(_options.Value.CustomFarewell))
{
return _options.Value.CustomFarewell;
}
return "Farewell!";
}
}
}
Gets me much closer - from my initial list I can do everything except configure services from the command line.
For my contrived example, --farewell Bye!
should change the program's output to
Hello!
Bye!
Do you know if there is a working example where multiple commands/handlers are wired with host.UseCommandHandler<,>
?
Does this test case help illustrate the usage?
Does this test case help illustrate the usage?
Sort of, I don't think it shows how to get access to multiple services though.
One scenario I wasn't quite able to figure out myself was if my root command wanted to leverage constructor DI, I wasn't seeing how to implement that when you need to create an instance of the root to pass into the CommandLineBuilder constructor.
Or is it simply root commands have to be constrained to something very simplistic and they should be thought of as more of an 'anchor point' for your set of top-level sub-commands than providing functionality in the root itself.
I have started work on PR #2450 where I will add new examples to HostingPlyground
on how to use the .NET Generic Host. This PR also introduces a new feature that provides first-class support for using a Hosted service for executing your CLI Command.
I'm lost in the weeds with dependency injection here.
Before I even get to using the Hosting stuff, why is RootCommand set to Test2 when that's not in
args[]
and why aren'tMyCommand
andMyCommandHandler
not called at all - shouldn't I be getting aNotImplementedException
?I've looked at https://github.com/dotnet/command-line-api/blob/5618b2d243ccdeb5c7e50a298b33b13036b4351b/src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs and https://github.com/dotnet/command-line-api/issues/1025#issuecomment-678609352 but have not been able to make much progress.
https://learn.microsoft.com/en-us/dotnet/standard/commandline/dependency-injection isn't entirely suitable because I need multiple services after my command line is parsed.
Further away from my simplified example, I'd like something like the following to work:
So I am stuck on:
Thanks in advance - sorry if I've completely missed the mark here.