Skip to content

Dependency injection confusion - How to use CommandLineBuilder, UseHost, CommandHandlers etc #1858

Open
@voltagex

Description

@voltagex

I'm lost in the weeds with dependency injection here.

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)
        {
            CommandLineBuilder builder = new CommandLineBuilder();
            var parser = builder.UseHost((host) => {
                host.UseCommandHandler<MyCommand, MyCommandHandler>();
            }).Build();

            var parseResult = parser.Parse(args);
            var invokeResult = parser.Invoke(args);
        }
    }

    internal class MyCommandHandler : ICommandHandler
    {
        public int Invoke(InvocationContext context)
        {
            throw new NotImplementedException();
        }

        public Task<int> InvokeAsync(InvocationContext context)
        {
            throw new NotImplementedException();
        }
    }

    internal class MyCommand : Command
    {
        public MyCommand() : base("Test2")
        {

        }
    }

    public interface IHelloService
    {
        string Hello();
    }

    public class HelloService : IHelloService
    {
        public HelloService()
        {
        }

        public string Hello()
        {
            return "Hello!";
        }
    }
}

Before I even get to using the Hosting stuff, why is RootCommand set to Test2 when that's not in args[] and why aren't MyCommand and MyCommandHandler not called at all - shouldn't I be getting a NotImplementedException?

I've looked at https://github.com/dotnet/command-line-api/blob/5618b2d243ccdeb5c7e50a298b33b13036b4351b/src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs and #1025 (comment) 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:

        var parser = commandBuilder.UseHost(host => host.ConfigureDefaults(args).ConfigureServices(s=> 
        {
            s.AddLogging(l=> l.AddConsole());
            s.AddOptions();
            s.AddOptions<DatabaseOptions>();
            s.Configure<DatabaseOptions>(c => c.ConnectionString = "Data Source=mydatabase.db");
            //Bind --host 127.0.0.1 to configuration somehow
           //s.Configure<RemoteHostOptions>(h=> h.Host = ParseResult.GetOption(...))
            s.AddSingleton<IFilesDatabase, FilesDatabase>();
        }).UseCommandHandler<ScanCommand, ScanCommandHandler>()).Build();

So I am stuck on:

  1. Parsing command line options and arguments
  2. Getting access to services in an IHost's ServiceCollection
  3. Converting command lines to configuration for services
  4. Invoking it all and having it "just work"

Thanks in advance - sorry if I've completely missed the mark here.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions