Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of how to define commands that require components to be injected #43

Closed
ninjaboy opened this issue Jan 23, 2018 · 4 comments
Closed
Milestone

Comments

@ninjaboy
Copy link

hi @natemcmaster ,

I am struggling to find an example of how it is envisioned to define commands that accept custom dependencies injected using declarative syntax.
Is there any place where you could point me to see an example of how to do this?

@ninjaboy
Copy link
Author

ninjaboy commented Jan 23, 2018

To clarify myself:
app.Execute only accepts command type to be execute, andthere's no way to control the creation of the command itself provided by the library
Is my understanding right?

I ended up creating a weird closure to perform injection in the form of:

        private static CommandLineApplication DefineApp(IContainer container)
        {
            var app = new CommandLineApplication
            {
            };
            app.Command("m", cmd => MCommand.ConfigureCommand(container, cmd), false);
            return app;
         }


public class M{

   public M(...dependencies injected here...)
         { this.dep1 = dep1; }

    public Do(int n)
    {  dep1.Do(n);  }

    public static void ConfigureCommand(IContainer container, CommandLineApplication command)
        {
            var number = command.Argument("n", "number").IsRequired();
            command.HelpOption();
            command.OnExecute(() =>
            {
                CommandExecuteHandler(container, command, number);
            });
        }
        private static void CommandExecuteHandler(IContainer container, CommandLineApplication command, CommandArgument number)
        {
            try
            {
                var commandContext = container.Resolve<M>();
               commandContext.Do(number);
             } catch(){}
       }
}

This resolves dependency injection but obviously requires too much boilerplate to wire up simple things.

AND prevents me from using declarative API syntax

@natemcmaster
Copy link
Owner

I haven't currently created a way to do this. The current requirement for .Execute<TApp>() is that type TApp has a parameter-less constructor.

But, if I were to do this, I would favor constructor injection and add an overload like .Execute<TApp>(System.IServiceProvider services, string[] args). Would supporting something like this work?

class Program
{
    public static int Main(string[] args)
    {
        System.IServiceProvider container = CreateServiceContainer();
        return CommandLineApplication.Execute<App>(container, args);
    }

    static System.IServiceProvider CreateServiceContainer()
    {
        // ... 
    }
}

class App
{
    public App(ManifestCommand command,IContainer container, ILogger logger)
    { }

    [Argument(0)]
    public int Number { get; }
}

@kt81
Copy link

kt81 commented Feb 13, 2018

@natemcmaster
I like your plan.

btw, the DI sample in this site works correctly.
https://brainwipe.github.io/dotnet/core/marten/2017/11/07/injecting-logging-into-marten/
But, it requires to instantiate all commands without ReflectionAppBuilder so attribute-based settings are ignored.

@natemcmaster
Copy link
Owner

I've added support for this. See the sample I wrote here: https://github.com/natemcmaster/CommandLineUtils/blob/cc4d6015bb91eb16f2cb2bb867b858fe0f979d8c/samples/Conventions/DependencyInjection.cs

This will be out in 2.2.0-beta, or you can try the nightly builds (see README). Give it a shot and let me know if it works for you.

@natemcmaster natemcmaster added this to the 2.2.0 milestone Mar 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants