Skip to content

Question: Usage models with Service Collection (not using Generic Host) #1455

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

Open
Simonl9l opened this issue Oct 30, 2021 · 9 comments
Open

Comments

@Simonl9l
Copy link

I have been using a different cli library, that has some great features, and is very usable, but lacks functionality such as tab completion (per dotnetsuggest`) However it does work well with using a raw ServiceCollection and provides the ability to inject those services into commands.

Im assessing the lift to migrate.

I see that command-line-api has Host Builder support (via .UseHost by scanning issues - open and closed) bit not specific documentation.

Are there any examples out there of just using the ServiceCollection with DI support (the other library uses reflection)?

One hopes in-time that (as other libraries) the DI integration is not tightly integrated such that one can use different services containers (albeit in the other library once would need to write a custom Convention vs the included DI one to achieve this) ?

@Simonl9l Simonl9l changed the title Question: Usage models with Service Collection (no using Generic Host) Question: Usage models with Service Collection (not using Generic Host) Oct 30, 2021
@jonsequitur
Copy link
Contributor

I've been distracted from looking at the Hosting package lately while we work on stabilizing the core library, but playing nicely with DI is definitely an important goal.

@fredrikhr Do we have a good sample for this, potentially including the proposed API changes in the open PRs (e.g. #1356)? I think a how-to document would be very helpful in assessing the overall shape of the API and the proposed changes.

@Simonl9l
Copy link
Author

Simonl9l commented Oct 30, 2021

@jonsequitur @fredrikhr thanks for the speedy reply!

Per the item linked, I'm specifically looking at not using any HostBuilder, Generic or otherwise from dotnet Core. I don't need the weight of that and am managing lifecycles of my use cases.

Im not using hosted services and am not using configuration, or and logical startup.cs. On face value as it stand the .UseHost is not apparently helpful in this regard?...

However if you do have any examples that just work with a built service collection in perhaps a similar way to this, that would be great...

@jonsequitur
Copy link
Contributor

You can do something like the following and delegate the call to your IServiceProvider:

 var commandLineBuilder =
                    new CommandLineBuilder(rootCommand)
                        .UseDefaults()
                        .UseMiddleware(
                            context =>
                            {
                                context.BindingContext.AddService(
                                           typeof(MyService),
                                           theSystemCommandLineServiceProvider => yourServiceProvider.GetService(typeof(MyService)));
                            });

This is a deliberately limited shim to provide your own services when binding and shouldn't be seen as a way to replace the System.CommandLine implementations (e.g. InvocationContext). This is why there's no catch-all for all possible types. No lifetime management, subtype mapping, open generic support, etc. is provided.

@Simonl9l
Copy link
Author

@jonsequitur thanks...

So I can then "inject" that service into the ICommandHandler implementations constructor?

From a lifecycle perspective, I create, configure and build the service collection up front, and and Dispose it after the IinvokeAsync it seems.

I've not looked at coding anything as yet, just looking at feasibility. I'd suggest something a bit more generic that perhaps reflects the services from the service collection dynamically based on the command handlers constructor, might be a consideration of a future feature.

However any approach there may need to be configurable as your currently suggested approach is obviously DI container agnostic.

I'd only otherwise suggest that having a Generic function that would say allow you to do this (sorta) might be better syntactic sugar...to remove the typeof's:

ar commandLineBuilder =
                    new CommandLineBuilder(rootCommand)
                        .UseDefaults()
                        .UseMiddleware(
                            context =>
                            {
                                context.BindingContext.AddService<MyService>(
                                           theSystemCommandLineServiceProvider => yourServiceProvider.GetRequiredService<MyService>();
                            });

however I'm slightly lost as to the difference between theSystemCommandLineServiceProvider and yourServiceProvider.GetRequiredService in your specific example.

@jonsequitur
Copy link
Contributor

You can inject into the handler method. Injection into command handlers isn't supported by default but it's not hard to do. #1356 has an example using the generic host but that's not required. Generally though we've leaned toward services and arguments being bound to a handler single method, which also happens to align to the minimal web API design.

I've not looked at coding anything as yet, just looking at feasibility. I'd suggest something a bit more generic that perhaps reflects the services from the service collection dynamically based on the command handlers constructor, might be a consideration of a future feature.

We're heading in this direction with our source generator support: https://github.com/dotnet/command-line-api/tree/main/src/System.CommandLine.Generator.

I'd only otherwise suggest that having a Generic function that would say allow you to do this (sorta) might be better syntactic sugar...to remove the typeof's:

There is a generically-typed overload.

@Simonl9l
Copy link
Author

Simonl9l commented Nov 6, 2021

@jonsequitur thanks for the help, I think I can probably make things work!

TBH I'd rather re-structure code not to integrate services into the CLI commands but the other way around, and construct the needed service container on an as needed basis dependent on the command's needs.

However when is the package destined for a non pre-release version ?

@Simonl9l
Copy link
Author

Simonl9l commented Nov 7, 2021

Actually, the docs need a lot of work...

Define the difference and capabilities for Command, Options, Arguments etc. would be a start...

Digging around the open/closed issues for examples based on others questions is is not really helpful.

@jonsequitur
Copy link
Contributor

Did you happen on this and is it helpful at all? https://github.com/dotnet/command-line-api/blob/main/docs/Syntax-Concepts-and-Parser.md

@Simonl9l
Copy link
Author

Simonl9l commented Nov 7, 2021

Helpful of course, but not an exhaustively complete API guide, that covers things like IFileInfo and extensions like .ExistingOnly and anything similar that once seems to only find searching the issues/questions.

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

2 participants