natemcmaster / CommandLineUtils

Command line parsing and utilities for .NET

Home Page:https://natemcmaster.github.io/CommandLineUtils/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Startup error: sub-commands with references to parent and application service

nkilzer opened this issue · comments

Describe the bug
When using the dependency-injection + generic-host support, creating subcommands that reference a parent command for options or behavior cause an exception on startup when constructing CommandLineApplication as part of initializing CommandLineService here:

_application = new CommandLineApplication<T>(state.Console, state.WorkingDirectory);
_application.Conventions
.UseDefaultConventions()
.UseConstructorInjection(serviceProvider);
.

 ---> System.InvalidOperationException: The constructor of type '[[CommandClass]]' contains the parameter of type '[[DependencyClass]]' is not registered, Ensure the type '[[DependencyClass]]' are registered in additional services with CommandLineApplication.Conventions.UseConstructorInjection(IServiceProvider additionalServices).
   at McMaster.Extensions.CommandLineUtils.Conventions.ConstructorInjectionConvention.<>c__DisplayClass6_1`1.<FindMatchedConstructor>b__3()
   at McMaster.Extensions.CommandLineUtils.CommandLineApplication`1.CreateModel()

The reproduction does not require attempting to execute the specific sub-sub-command that has the additional dependency. The exception occurs when constructing the application model during the initial phase of the run sequence.

The root cause appears to be that the Lazyproperty is resolved early in CommandLineApplication before the service provider conventions can be registered, and so the ModelFactory does not have access to the application IServiceProvider via AdditionalServices. The triggering point appears to be the application of the ConstructorInjectionConvention within the UseDefaultConventions method, as it iterates over the subcommands of the model. The iteration triggers the attempt to build the constructor invokation delegate for the sub-command, which requires resolving all dependencies.

A possible fix would be to provide an IServiceProvider to UseDefaultConventions (maybe in an internal-only variant) that negates the need for the extra UseConstructorInjection call after the application model is constructed, and makes the provider available during constructor resolution.

Another fix might be to require commands to be registered in the application service provider, and use it's resolution mechanisms to construct the actual command instances for execution. This may be complicated by the flow of setting options before execution. It would also likely be a breaking change for consumers.

To Reproduce
Steps to reproduce the behavior:
Create a project:
Runtime: .NET Core 3.1 or .NET 5.0 (tested on Windows, but probably cross-platform)
McMaster.Extensions.Hosting.CommandLine 3.1.0

Create a parent command to represent the application.
Create a sub-command to represent an application behavior group.
Create a sub-sub-command to perform a specific application action.

Add a constructor reference to the sub-command in the sub-sub-command.
Add a constructor reference to another dependency from the application container in the sub-sub-command.

Expected behavior
Constructor injection to be performed on both parameters in the sub-sub-command, allowing access to the parent command options and behavior, and successful execution of the application.

Additional context
Demo project repository can be found here: https://github.com/nkilzer/cli-injection-error-demo

Seems like a bug. Marking as help-wanted. Feel free to proposes a pull request to fix it.

This issue has been automatically marked as stale because it has no recent activity. It will be closed if no further activity occurs. Please comment if you believe this should remain open, otherwise it will be closed in 14 days. Thank you for your contributions to this project.

Closing due to inactivity.
If you are looking at this issue in the future and think it should be reopened, please make a commented here and mention natemcmaster so he sees the notification.