diff --git a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_NamingConventionBinder_api_is_not_changed.approved.txt b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_NamingConventionBinder_api_is_not_changed.approved.txt index a8c045b3dd..613415b35f 100644 --- a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_NamingConventionBinder_api_is_not_changed.approved.txt +++ b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_NamingConventionBinder_api_is_not_changed.approved.txt @@ -1,74 +1,94 @@ -System.CommandLine.NamingConventionBinder +System.CommandLine.Binding + public class BindingContext, System.IServiceProvider + public System.CommandLine.IConsole Console { get; } + public System.CommandLine.ParseResult ParseResult { get; } + public System.Void AddService(System.Type serviceType, System.Func factory) + public System.Void AddService(Func factory) + public System.Object GetService(System.Type serviceType) + public struct BoundValue : System.ValueType + public System.Object Value { get; } + public IValueDescriptor ValueDescriptor { get; } + public IValueSource ValueSource { get; } + public System.String ToString() + public interface IValueSource + public System.Boolean TryGetValue(IValueDescriptor valueDescriptor, BindingContext bindingContext, ref System.Object& boundValue) +System.CommandLine.NamingConventionBinder public static class BindingContextExtensions public static System.Void AddModelBinder(this System.CommandLine.Binding.BindingContext bindingContext, ModelBinder binder) + public static System.CommandLine.Binding.BindingContext GetBindingContext(this System.CommandLine.Invocation.InvocationContext ctx) public static ModelBinder GetOrCreateModelBinder(this System.CommandLine.Binding.BindingContext bindingContext, System.CommandLine.Binding.IValueDescriptor valueDescriptor) + public abstract class BindingHandler, System.CommandLine.ICommandHandler + public System.CommandLine.Binding.BindingContext GetBindingContext(System.CommandLine.Invocation.InvocationContext invocationContext) + public System.Int32 Invoke(System.CommandLine.Invocation.InvocationContext context) + public System.Threading.Tasks.Task InvokeAsync(System.CommandLine.Invocation.InvocationContext context, System.Threading.CancellationToken cancellationToken = null) + public System.CommandLine.Binding.BindingContext SetBindingContext(System.CommandLine.Binding.BindingContext bindingContext) public static class CommandHandler - public static System.CommandLine.ICommandHandler Create(System.Delegate delegate) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Action action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(Func> action) - public static System.CommandLine.ICommandHandler Create(System.Reflection.MethodInfo method, System.Object target = null) + public static BindingHandler Create(System.Delegate delegate) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Action action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(Func> action) + public static BindingHandler Create(System.Reflection.MethodInfo method, System.Object target = null) public class ConstructorDescriptor, IMethodDescriptor public System.Collections.Generic.IReadOnlyList ParameterDescriptors { get; } public ModelDescriptor Parent { get; } @@ -78,7 +98,7 @@ public static HandlerDescriptor FromMethodInfo(System.Reflection.MethodInfo methodInfo, System.Object target = null) public System.Collections.Generic.IReadOnlyList ParameterDescriptors { get; } public ModelDescriptor Parent { get; } - public System.CommandLine.ICommandHandler GetCommandHandler() + public BindingHandler GetCommandHandler() public System.String ToString() public interface IMethodDescriptor public System.Collections.Generic.IReadOnlyList ParameterDescriptors { get; } @@ -95,7 +115,7 @@ .ctor() public System.Void BindMemberFromValue(Expression> property, System.CommandLine.Binding.IValueDescriptor valueDescriptor) public System.Void BindMemberFromValue(Expression> property, Func getValue) - public class ModelBindingCommandHandler, System.CommandLine.ICommandHandler + public class ModelBindingCommandHandler : BindingHandler, System.CommandLine.ICommandHandler public System.Void BindParameter(System.Reflection.ParameterInfo param, System.CommandLine.Argument argument) public System.Void BindParameter(System.Reflection.ParameterInfo param, System.CommandLine.Option option) public System.Int32 Invoke(System.CommandLine.Invocation.InvocationContext context) diff --git a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt index a2fddaf5a3..2ea409d1ac 100644 --- a/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt +++ b/src/System.CommandLine.ApiCompatibility.Tests/ApiCompatibilityApprovalTests.System_CommandLine_api_is_not_changed.approved.txt @@ -73,7 +73,7 @@ System.CommandLine public CommandLineBuilder UseHelp(System.Nullable maxWidth = null) public CommandLineBuilder UseHelp(System.String name, System.String[] helpAliases) public CommandLineBuilder UseHelp(System.Action customize, System.Nullable maxWidth = null) - public CommandLineBuilder UseHelpBuilder(System.Func getHelpBuilder) + public CommandLineBuilder UseHelpBuilder(System.Func getHelpBuilder) public CommandLineBuilder UseParseDirective(System.Int32 errorExitCode = 1) public CommandLineBuilder UseParseErrorReporting(System.Int32 errorExitCode = 1) public CommandLineBuilder UseSuggestDirective() @@ -83,7 +83,7 @@ System.CommandLine public CommandLineBuilder UseVersionOption(System.String name, System.String[] aliases) public class CommandLineConfiguration public static CommandLineBuilder CreateBuilder(Command rootCommand) - .ctor(Command command, System.Boolean enablePosixBundling = True, System.Boolean enableTokenReplacement = True, System.Collections.Generic.IReadOnlyList middlewarePipeline = null, System.Func helpBuilderFactory = null, System.CommandLine.Parsing.TryReplaceToken tokenReplacer = null) + .ctor(Command command, System.Boolean enablePosixBundling = True, System.Boolean enableTokenReplacement = True, System.Collections.Generic.IReadOnlyList middlewarePipeline = null, System.Func helpBuilderFactory = null, System.CommandLine.Parsing.TryReplaceToken tokenReplacer = null) public System.Collections.Generic.IReadOnlyList Directives { get; } public System.Boolean EnablePosixBundling { get; } public System.Boolean EnableTokenReplacement { get; } @@ -172,24 +172,11 @@ System.CommandLine public System.Collections.Generic.IEnumerable GetCompletions(System.CommandLine.Completions.CompletionContext context) public System.String ToString() System.CommandLine.Binding - public class BindingContext, System.IServiceProvider - public System.CommandLine.IConsole Console { get; } - public System.CommandLine.ParseResult ParseResult { get; } - public System.Void AddService(System.Type serviceType, System.Func factory) - public System.Void AddService(Func factory) - public System.Object GetService(System.Type serviceType) - public struct BoundValue : System.ValueType - public System.Object Value { get; } - public IValueDescriptor ValueDescriptor { get; } - public IValueSource ValueSource { get; } - public System.String ToString() public interface IValueDescriptor public System.Boolean HasDefaultValue { get; } public System.String ValueName { get; } public System.Type ValueType { get; } public System.Object GetDefaultValue() - public interface IValueSource - public System.Boolean TryGetValue(IValueDescriptor valueDescriptor, BindingContext bindingContext, ref System.Object& boundValue) System.CommandLine.Completions public abstract class CompletionContext public static CompletionContext Empty { get; } @@ -253,7 +240,6 @@ System.CommandLine.Help System.CommandLine.Invocation public class InvocationContext .ctor(System.CommandLine.ParseResult parseResult, System.CommandLine.IConsole console = null) - public System.CommandLine.Binding.BindingContext BindingContext { get; } public System.CommandLine.IConsole Console { get; set; } public System.Int32 ExitCode { get; set; } public System.CommandLine.Help.HelpBuilder HelpBuilder { get; } diff --git a/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs b/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs index c9a6e50fce..91796ac8f4 100644 --- a/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs +++ b/src/System.CommandLine.Generator.Tests/GeneratedCommandHandlerTests.cs @@ -136,25 +136,22 @@ public async Task Can_generate_handler_with_well_know_parameters_types() IConsole? boundConsole = null; ParseResult? boundParseResult = null; HelpBuilder? boundHelpBuilder = null; - BindingContext? boundBindingContext = null; void Execute( InvocationContext invocationContext, IConsole console, ParseResult parseResult, - HelpBuilder helpBuilder, - BindingContext bindingContext) + HelpBuilder helpBuilder) { boundInvocationContext = invocationContext; boundConsole = console; boundParseResult = parseResult; boundHelpBuilder = helpBuilder; - boundBindingContext = bindingContext; } var command = new Command("command"); - command.SetHandler>(Execute); + command.SetHandler>(Execute); await command.InvokeAsync("command", _console); @@ -162,7 +159,6 @@ void Execute( boundConsole.Should().Be(_console); boundParseResult.Should().NotBeNull(); boundHelpBuilder.Should().NotBeNull(); - boundBindingContext.Should().NotBeNull(); } [Fact] diff --git a/src/System.CommandLine.Generator/Parameters/BindingContextParameter.cs b/src/System.CommandLine.Generator/Parameters/BindingContextParameter.cs index 4e8b75a9bd..2614007971 100644 --- a/src/System.CommandLine.Generator/Parameters/BindingContextParameter.cs +++ b/src/System.CommandLine.Generator/Parameters/BindingContextParameter.cs @@ -10,7 +10,7 @@ public BindingContextParameter(ITypeSymbol bindingContextType) } public override string GetValueFromContext() - => "context.BindingContext"; + => "context.GetBindingContext()"; public override int GetHashCode() => base.GetHashCode(); diff --git a/src/System.CommandLine.Generator/WellKnownTypes.cs b/src/System.CommandLine.Generator/WellKnownTypes.cs index fda81b51ad..8586491283 100644 --- a/src/System.CommandLine.Generator/WellKnownTypes.cs +++ b/src/System.CommandLine.Generator/WellKnownTypes.cs @@ -13,7 +13,6 @@ internal class WellKnownTypes public INamedTypeSymbol ParseResult { get; } public INamedTypeSymbol InvocationContext { get; } public INamedTypeSymbol HelpBuilder { get; } - public INamedTypeSymbol BindingContext { get; } public IEqualityComparer Comparer { get; } public WellKnownTypes(Compilation compilation, IEqualityComparer comparer) @@ -22,7 +21,6 @@ public WellKnownTypes(Compilation compilation, IEqualityComparer compa ParseResult = GetType("System.CommandLine.ParseResult"); InvocationContext = GetType("System.CommandLine.Invocation.InvocationContext"); HelpBuilder = GetType("System.CommandLine.Help.HelpBuilder"); - BindingContext = GetType("System.CommandLine.Binding.BindingContext"); INamedTypeSymbol GetType(string typeName) => compilation.GetTypeByMetadataName(typeName) @@ -59,9 +57,9 @@ internal bool TryGet(ISymbol symbol, out Parameter? parameter) return true; } - if (Comparer.Equals(BindingContext, symbol)) + if (symbol.MetadataName == "System.CommandLine.Binding.BindingContext" && symbol is INamedTypeSymbol bindingContext) { - parameter = new BindingContextParameter(BindingContext); + parameter = new BindingContextParameter(bindingContext); return true; } diff --git a/src/System.CommandLine.Hosting/HostingExtensions.cs b/src/System.CommandLine.Hosting/HostingExtensions.cs index 93573e7332..9abf1a7554 100644 --- a/src/System.CommandLine.Hosting/HostingExtensions.cs +++ b/src/System.CommandLine.Hosting/HostingExtensions.cs @@ -31,10 +31,11 @@ public static CommandLineBuilder UseHost(this CommandLineBuilder builder, { config.AddCommandLineDirectives(invocation.ParseResult, configurationDirective); }); + var bindingContext = invocation.GetBindingContext(); hostBuilder.ConfigureServices(services => { services.AddSingleton(invocation); - services.AddSingleton(invocation.BindingContext); + services.AddSingleton(bindingContext); services.AddSingleton(invocation.Console); services.AddTransient(_ => invocation.InvocationResult); services.AddTransient(_ => invocation.ParseResult); @@ -44,7 +45,7 @@ public static CommandLineBuilder UseHost(this CommandLineBuilder builder, using var host = hostBuilder.Build(); - invocation.BindingContext.AddService(typeof(IHost), _ => host); + bindingContext.AddService(typeof(IHost), _ => host); await host.StartAsync(cancellationToken); @@ -109,13 +110,16 @@ public static IHostBuilder UseCommandHandler(this IHostBuilder builder, Type com && invocation.ParseResult.CommandResult.Command is Command command && command.GetType() == commandType) { - invocation.BindingContext.AddService(handlerType, c => c.GetService().Services.GetService(handlerType)); builder.ConfigureServices(services => { services.AddTransient(handlerType); }); - command.Handler = CommandHandler.Create(handlerType.GetMethod(nameof(ICommandHandler.InvokeAsync))); + BindingHandler bindingHandler = CommandHandler.Create(handlerType.GetMethod(nameof(ICommandHandler.InvokeAsync))); + // NullBindingHandler that accumulated services registered so far, before handler creation + bindingHandler.SetBindingContext(command.Handler is BindingHandler pre ? pre.GetBindingContext(invocation) : null); + command.Handler = bindingHandler; + bindingHandler.GetBindingContext(invocation).AddService(handlerType, c => c.GetService().Services.GetService(handlerType)); } return builder; @@ -147,7 +151,7 @@ public static IHost GetHost(this InvocationContext invocationContext) { _ = invocationContext ?? throw new ArgumentNullException(paramName: nameof(invocationContext)); var hostModelBinder = new ModelBinder(); - return (IHost)hostModelBinder.CreateInstance(invocationContext.BindingContext); + return (IHost)hostModelBinder.CreateInstance(invocationContext.GetBindingContext()); } } } diff --git a/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs b/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs index ab3be94522..5d2a97e273 100644 --- a/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs +++ b/src/System.CommandLine.NamingConventionBinder.Tests/ModelBinderTests.cs @@ -33,7 +33,7 @@ public void Option_arguments_are_bound_by_name_to_constructor_parameters( OptionBuilder.CreateOption("--value", type) }; - var bindingContext = new InvocationContext(command.Parse(commandLine)).BindingContext; + var bindingContext = new InvocationContext(command.Parse(commandLine)).GetBindingContext(); var instance = binder.CreateInstance(bindingContext); @@ -60,7 +60,7 @@ public void Command_arguments_are_bound_by_name_to_constructor_parameters( ArgumentBuilder.CreateArgument(type) }; - var bindingContext = new InvocationContext(command.Parse(commandLine)).BindingContext; + var bindingContext = new InvocationContext(command.Parse(commandLine)).GetBindingContext(); var instance = binder.CreateInstance(bindingContext); @@ -83,7 +83,7 @@ public void Command_arguments_are_bound_by_name_to_complex_constructor_parameter ArgumentBuilder.CreateArgument(type) }; - var bindingContext = new InvocationContext(command.Parse(commandLine)).BindingContext; + var bindingContext = new InvocationContext(command.Parse(commandLine)).GetBindingContext(); var instance = binder.CreateInstance(bindingContext); @@ -107,7 +107,7 @@ public void Explicitly_configured_default_values_can_be_bound_by_name_to_constru command.Options.Add(option); var binder = new ModelBinder(typeof(ClassWithMultiLetterCtorParameters)); - var bindingContext = new InvocationContext(Parser.Parse(command, "")).BindingContext; + var bindingContext = new InvocationContext(Parser.Parse(command, "")).GetBindingContext(); var instance = (ClassWithMultiLetterCtorParameters)binder.CreateInstance(bindingContext); @@ -132,7 +132,7 @@ public void Option_arguments_are_bound_by_name_to_property_setters( OptionBuilder.CreateOption("--value", type) }; - var bindingContext = new InvocationContext(command.Parse(commandLine)).BindingContext; + var bindingContext = new InvocationContext(command.Parse(commandLine)).GetBindingContext(); var instance = binder.CreateInstance(bindingContext); @@ -159,7 +159,7 @@ public void Command_arguments_are_bound_by_name_to_property_setters( ArgumentBuilder.CreateArgument(type) }; - var bindingContext = new InvocationContext(command.Parse(commandLine)).BindingContext; + var bindingContext = new InvocationContext(command.Parse(commandLine)).GetBindingContext(); var instance = binder.CreateInstance(bindingContext); @@ -178,7 +178,7 @@ public void Types_having_constructors_accepting_a_single_string_are_bound_using_ var command = new Command("the-command"); command.Options.Add(option); var binder = new ModelBinder(typeof(ClassWithCtorParameter)); - var bindingContext = new InvocationContext(command.Parse($"--value \"{tempPath}\"")).BindingContext; + var bindingContext = new InvocationContext(command.Parse($"--value \"{tempPath}\"")).GetBindingContext(); var instance = (ClassWithCtorParameter)binder.CreateInstance(bindingContext); @@ -194,7 +194,7 @@ public void Explicitly_configured_default_values_can_be_bound_by_name_to_propert command.Options.Add(option); var binder = new ModelBinder(typeof(ClassWithSetter)); - var bindingContext = new InvocationContext(command.Parse("")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("")).GetBindingContext(); var instance = (ClassWithSetter)binder.CreateInstance(bindingContext); @@ -212,7 +212,7 @@ public void Property_setters_with_no_default_value_and_no_matching_option_are_no var binder = new ModelBinder(typeof(ClassWithSettersAndCtorParametersWithDifferentNames)); var bindingContext = new InvocationContext( - command.Parse("")).BindingContext; + command.Parse("")).GetBindingContext(); var instance = (ClassWithSettersAndCtorParametersWithDifferentNames)binder.CreateInstance(bindingContext); @@ -226,7 +226,7 @@ public void Parse_result_can_be_used_to_create_an_instance_without_doing_handler { new Option("--int-option") }; - var bindingContext = new InvocationContext(command.Parse("the-command --int-option 123")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("the-command --int-option 123")).GetBindingContext(); var binder = new ModelBinder(typeof(ClassWithMultiLetterSetters)); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -242,7 +242,7 @@ public void Parse_result_can_be_used_to_modify_an_existing_instance_without_doin new Option("--int-option") }; var instance = new ClassWithMultiLetterSetters(); - var bindingContext = new InvocationContext(command.Parse("the-command --int-option 123")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("the-command --int-option 123")).GetBindingContext(); var binder = new ModelBinder(typeof(ClassWithMultiLetterSetters)); binder.UpdateInstance(instance, bindingContext); @@ -256,7 +256,7 @@ public void Modify_an_existing_instance_should_keep_all_default_values_if_no_arg Command parser = new ("the-command"); var instance = new ClassWithComplexTypes(); - var bindingContext = new InvocationContext(parser.Parse("the-command")).BindingContext; + var bindingContext = new InvocationContext(parser.Parse("the-command")).GetBindingContext(); var binder = new ModelBinder(typeof(ClassWithComplexTypes)); binder.UpdateInstance(instance, bindingContext); @@ -277,7 +277,7 @@ public void Values_from_options_on_parent_commands_are_bound_by_name_by_default( var parseResult = parentCommand.Parse("parent-command --int-option 123 child-command"); - var bindingContext = new InvocationContext(parseResult).BindingContext; + var bindingContext = new InvocationContext(parseResult).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -300,7 +300,7 @@ public void Default_values_from_options_on_parent_commands_are_bound_by_name_by_ var parseResult = parentCommand.Parse("parent-command child-command"); - var bindingContext = new InvocationContext(parseResult).BindingContext; + var bindingContext = new InvocationContext(parseResult).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -320,7 +320,7 @@ public void Values_from_parent_command_arguments_are_bound_by_name_by_default() var parseResult = parentCommand.Parse("parent-command 123 child-command"); - var bindingContext = new InvocationContext(parseResult).BindingContext; + var bindingContext = new InvocationContext(parseResult).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -343,7 +343,7 @@ public void Default_values_from_parent_command_arguments_are_bound_by_name_by_de var parseResult = parentCommand.Parse("parent-command child-command"); - var bindingContext = new InvocationContext(parseResult).BindingContext; + var bindingContext = new InvocationContext(parseResult).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -367,7 +367,7 @@ public void Values_from_options_on_parent_commands_can_be_bound_regardless_of_na c => c.IntOption, option); - var bindingContext = new InvocationContext(parentCommand.Parse("parent-command -x 123 child-command")).BindingContext; + var bindingContext = new InvocationContext(parentCommand.Parse("parent-command -x 123 child-command")).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -385,7 +385,7 @@ public void Arbitrary_values_can_be_bound() c => c.IntOption, _ => 123); - var bindingContext = new InvocationContext(command.Parse("the-command")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("the-command")).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -407,7 +407,7 @@ public void PropertyInfo_can_be_bound_to_option() propertyInfo, option); - var bindingContext = new InvocationContext(command.Parse("the-command --fred 42")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("the-command --fred 42")).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -427,7 +427,7 @@ public void PropertyInfo_can_be_bound_to_argument() binder.BindMemberFromValue(propertyInfo, argument); - var bindingContext = new InvocationContext(command.Parse("the-command 42")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("the-command 42")).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -447,7 +447,7 @@ public void PropertyExpression_can_be_bound_to_option() i => i.IntOption, option); - var bindingContext = new InvocationContext(command.Parse("the-command --fred 42")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("the-command --fred 42")).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -467,7 +467,7 @@ public void PropertyExpression_can_be_bound_to_argument() i => i.IntOption, argument); - var bindingContext = new InvocationContext(command.Parse("the-command 42")).BindingContext; + var bindingContext = new InvocationContext(command.Parse("the-command 42")).GetBindingContext(); var instance = (ClassWithMultiLetterSetters)binder.CreateInstance(bindingContext); @@ -479,7 +479,7 @@ public void Option_argument_is_bound_to_longest_constructor() { var option = new Option("--int-property"); - var bindingContext = new InvocationContext(new RootCommand { option }.Parse("--int-property 42")).BindingContext; + var bindingContext = new InvocationContext(new RootCommand { option }.Parse("--int-property 42")).GetBindingContext(); var binder = new ModelBinder(); var instance = binder.CreateInstance(bindingContext) as ClassWithMultipleCtor; @@ -493,7 +493,7 @@ public void Command_argument_is_bound_to_longest_constructor() var rootCommand = new RootCommand(); rootCommand.Arguments.Add(new Argument(nameof(ClassWithMultipleCtor.IntProperty))); - var bindingContext = new InvocationContext(rootCommand.Parse("42")).BindingContext; + var bindingContext = new InvocationContext(rootCommand.Parse("42")).GetBindingContext(); var binder = new ModelBinder(); var instance = binder.CreateInstance(bindingContext) as ClassWithMultipleCtor; @@ -508,7 +508,7 @@ public void Explicit_model_binder_binds_only_to_configured_properties() var stringOption = new Option("--string-property"); RootCommand rootCommand = new RootCommand { intOption, stringOption }; - var bindingContext = new InvocationContext(rootCommand.Parse("--int-property 42 --string-property Hello")).BindingContext; + var bindingContext = new InvocationContext(rootCommand.Parse("--int-property 42 --string-property Hello")).GetBindingContext(); var binder = new ModelBinder { EnforceExplicitBinding = true @@ -601,62 +601,6 @@ int Handler(IEnumerable names) } } - [Fact] - public void Custom_ModelBinders_specified_via_BindingContext_can_be_used_for_option_binding() - { - ClassWithSetter boundInstance = null; - - var rootCommand = new RootCommand - { - new Option("--value") - }; - - rootCommand.Handler = CommandHandler.Create>(x => boundInstance = x); - - var config = new CommandLineBuilder(rootCommand) - .AddMiddleware(context => - { - var binder = new ModelBinder>(); - - binder.BindMemberFromValue(instance => instance.Value, _ => 456); - - context.BindingContext.AddModelBinder(binder); - }) - .Build(); - - config.Invoke("--value 123"); - - boundInstance.Value.Should().Be(456); - } - - [Fact] - public void Custom_ModelBinders_specified_via_BindingContext_can_be_used_for_command_argument_binding() - { - ClassWithSetter boundInstance = null; - - var rootCommand = new RootCommand - { - new Argument("arg") - }; - - rootCommand.Handler = CommandHandler.Create>(x => boundInstance = x); - - var config = new CommandLineBuilder(rootCommand) - .AddMiddleware(context => - { - var binder = new ModelBinder>(); - - binder.BindMemberFromValue(instance => instance.Value, _ => 456); - - context.BindingContext.AddModelBinder(binder); - }) - .Build(); - - config.Invoke("123"); - - boundInstance.Value.Should().Be(456); - } - [Fact] public void Default_values_from_options_with_the_same_type_are_bound_and_use_their_own_defaults() { diff --git a/src/System.CommandLine/Binding/BindingContext.cs b/src/System.CommandLine.NamingConventionBinder/BindingContext.cs similarity index 100% rename from src/System.CommandLine/Binding/BindingContext.cs rename to src/System.CommandLine.NamingConventionBinder/BindingContext.cs diff --git a/src/System.CommandLine.NamingConventionBinder/BindingContextExtensions.cs b/src/System.CommandLine.NamingConventionBinder/BindingContextExtensions.cs index 92d26539b2..54ccace357 100644 --- a/src/System.CommandLine.NamingConventionBinder/BindingContextExtensions.cs +++ b/src/System.CommandLine.NamingConventionBinder/BindingContextExtensions.cs @@ -2,6 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.CommandLine.Binding; +using System.CommandLine.Invocation; +using System.Threading; +using System.Threading.Tasks; namespace System.CommandLine.NamingConventionBinder; @@ -10,6 +13,24 @@ namespace System.CommandLine.NamingConventionBinder; /// public static class BindingContextExtensions { + private sealed class DummyStateHoldingHandler : BindingHandler + { + public override int Invoke(InvocationContext context) => 0; + + public override Task InvokeAsync(InvocationContext context, CancellationToken cancellationToken = default) => Task.FromResult(0); + } + + public static BindingContext GetBindingContext(this InvocationContext ctx) + { + // parsing resulted with no handler or it was not created yet, we fake it to just store the BindingContext between the calls + if (ctx.ParseResult.CommandResult.Command.Handler is null) + { + ctx.ParseResult.CommandResult.Command.Handler = new DummyStateHoldingHandler(); + } + + return ((BindingHandler)ctx.ParseResult.CommandResult.Command.Handler).GetBindingContext(ctx); + } + /// /// Adds a model binder which can be used to bind a specific type. /// diff --git a/src/System.CommandLine.NamingConventionBinder/BindingHandler.cs b/src/System.CommandLine.NamingConventionBinder/BindingHandler.cs new file mode 100644 index 0000000000..a640932bf8 --- /dev/null +++ b/src/System.CommandLine.NamingConventionBinder/BindingHandler.cs @@ -0,0 +1,23 @@ +using System.CommandLine.Binding; +using System.CommandLine.Invocation; +using System.Threading; +using System.Threading.Tasks; + +namespace System.CommandLine.NamingConventionBinder +{ + public abstract class BindingHandler : ICommandHandler + { + private BindingContext? _bindingContext; + + /// + /// The binding context for the current invocation. + /// + public BindingContext GetBindingContext(InvocationContext invocationContext) => _bindingContext ??= new BindingContext(invocationContext); + + public BindingContext SetBindingContext(BindingContext bindingContext) => _bindingContext = bindingContext; + + public abstract int Invoke(InvocationContext context); + + public abstract Task InvokeAsync(InvocationContext context, CancellationToken cancellationToken = default); + } +} diff --git a/src/System.CommandLine/Binding/BoundValue.cs b/src/System.CommandLine.NamingConventionBinder/BoundValue.cs similarity index 100% rename from src/System.CommandLine/Binding/BoundValue.cs rename to src/System.CommandLine.NamingConventionBinder/BoundValue.cs diff --git a/src/System.CommandLine.NamingConventionBinder/CommandHandler.cs b/src/System.CommandLine.NamingConventionBinder/CommandHandler.cs index dbcf4daed9..1f2b94eb75 100644 --- a/src/System.CommandLine.NamingConventionBinder/CommandHandler.cs +++ b/src/System.CommandLine.NamingConventionBinder/CommandHandler.cs @@ -16,8 +16,8 @@ public static class CommandHandler /// Creates a command handler based on a delegate. /// /// The delegate to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create(Delegate @delegate) => + /// An instance of . + public static BindingHandler Create(Delegate @delegate) => HandlerDescriptor.FromDelegate(@delegate).GetCommandHandler(); /// @@ -25,16 +25,16 @@ public static ICommandHandler Create(Delegate @delegate) => /// /// The method to be called when the command handler is invoked. /// A target instance to be used if the specified method is an instance method. This can be null if the method is static. - /// An instance of . - public static ICommandHandler Create(MethodInfo method, object? target = null) => + /// An instance of . + public static BindingHandler Create(MethodInfo method, object? target = null) => HandlerDescriptor.FromMethodInfo(method, target).GetCommandHandler(); /// /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -42,8 +42,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -51,8 +51,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -60,8 +60,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -69,8 +69,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -78,8 +78,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -87,8 +87,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -96,8 +96,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -105,8 +105,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -114,8 +114,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -123,8 +123,8 @@ public static ICommandHandler Create( /// Creates a command handler based on an . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -132,8 +132,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -141,8 +141,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -150,8 +150,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -159,8 +159,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -168,8 +168,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Action action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -177,8 +177,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -186,8 +186,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -195,8 +195,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -204,8 +204,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -213,8 +213,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -222,8 +222,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -231,8 +231,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -240,8 +240,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -249,8 +249,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -258,8 +258,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -267,8 +267,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -276,8 +276,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -285,8 +285,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -294,8 +294,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -303,8 +303,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -312,8 +312,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -321,8 +321,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -330,8 +330,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -339,8 +339,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -348,8 +348,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -357,8 +357,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -366,8 +366,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -375,8 +375,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -384,8 +384,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -393,8 +393,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -402,8 +402,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -411,8 +411,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -420,8 +420,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -429,8 +429,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -438,8 +438,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -447,8 +447,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -456,8 +456,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -465,8 +465,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -474,8 +474,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -483,8 +483,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -492,8 +492,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -501,8 +501,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -510,8 +510,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -519,8 +519,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -528,8 +528,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -537,8 +537,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -546,8 +546,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -555,8 +555,8 @@ public static ICommandHandler Create( /// Creates a command handler based on a . /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -564,8 +564,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -573,8 +573,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -582,8 +582,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -591,8 +591,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); @@ -600,8 +600,8 @@ public static ICommandHandler Create. /// /// The to be called when the command handler is invoked. - /// An instance of . - public static ICommandHandler Create( + /// An instance of . + public static BindingHandler Create( Func> action) => HandlerDescriptor.FromDelegate(action).GetCommandHandler(); diff --git a/src/System.CommandLine.NamingConventionBinder/DelegateHandlerDescriptor.cs b/src/System.CommandLine.NamingConventionBinder/DelegateHandlerDescriptor.cs index 03ce3d96e6..f3d545043c 100644 --- a/src/System.CommandLine.NamingConventionBinder/DelegateHandlerDescriptor.cs +++ b/src/System.CommandLine.NamingConventionBinder/DelegateHandlerDescriptor.cs @@ -15,7 +15,7 @@ public DelegateHandlerDescriptor(Delegate handlerDelegate) _handlerDelegate = handlerDelegate; } - public override ICommandHandler GetCommandHandler() + public override BindingHandler GetCommandHandler() { return new ModelBindingCommandHandler( _handlerDelegate, diff --git a/src/System.CommandLine.NamingConventionBinder/HandlerDescriptor.cs b/src/System.CommandLine.NamingConventionBinder/HandlerDescriptor.cs index 5cb37c1adb..c833924234 100644 --- a/src/System.CommandLine.NamingConventionBinder/HandlerDescriptor.cs +++ b/src/System.CommandLine.NamingConventionBinder/HandlerDescriptor.cs @@ -14,7 +14,7 @@ public abstract class HandlerDescriptor : IMethodDescriptor /// /// Gets a command handler that can bind to the specifications of the descriptor. /// - public abstract ICommandHandler GetCommandHandler(); + public abstract BindingHandler GetCommandHandler(); /// public abstract ModelDescriptor? Parent { get; } diff --git a/src/System.CommandLine/Binding/IValueSource.cs b/src/System.CommandLine.NamingConventionBinder/IValueSource.cs similarity index 100% rename from src/System.CommandLine/Binding/IValueSource.cs rename to src/System.CommandLine.NamingConventionBinder/IValueSource.cs diff --git a/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs b/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs index 6f4e09e744..004c1a0c47 100644 --- a/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs +++ b/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs @@ -21,7 +21,7 @@ public MethodInfoHandlerDescriptor( _invocationTarget = target; } - public override ICommandHandler GetCommandHandler() + public override BindingHandler GetCommandHandler() { if (_invocationTarget is null) { diff --git a/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs b/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs index 97bf39bae4..d69576fd56 100644 --- a/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs +++ b/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs @@ -14,7 +14,7 @@ namespace System.CommandLine.NamingConventionBinder; /// /// Instantiates values to be passed to a user-defined command handler method. /// -public class ModelBindingCommandHandler : ICommandHandler +public class ModelBindingCommandHandler : BindingHandler { private readonly Delegate? _handlerDelegate; private readonly object? _invocationTarget; @@ -57,9 +57,9 @@ internal ModelBindingCommandHandler( /// The current invocation context. /// A token that can be used to cancel the invocation. /// A task whose value can be used to set the process exit code. - public async Task InvokeAsync(InvocationContext context, CancellationToken cancellationToken = default) + public override async Task InvokeAsync(InvocationContext context, CancellationToken cancellationToken = default) { - var bindingContext = context.BindingContext; + var bindingContext = GetBindingContext(context); var (boundValues, _) = ModelBinder.GetBoundValues( _invokeArgumentBindingSources, @@ -132,5 +132,5 @@ private void BindValueSource(ParameterInfo param, IValueSource valueSource) x.ValueType == param.ParameterType); /// - public int Invoke(InvocationContext context) => InvokeAsync(context, CancellationToken.None).GetAwaiter().GetResult(); + public override int Invoke(InvocationContext context) => InvokeAsync(context, CancellationToken.None).GetAwaiter().GetResult(); } \ No newline at end of file diff --git a/src/System.CommandLine/Invocation/ServiceProvider.cs b/src/System.CommandLine.NamingConventionBinder/ServiceProvider.cs similarity index 98% rename from src/System.CommandLine/Invocation/ServiceProvider.cs rename to src/System.CommandLine.NamingConventionBinder/ServiceProvider.cs index 2e96f4abe9..b08fa94934 100644 --- a/src/System.CommandLine/Invocation/ServiceProvider.cs +++ b/src/System.CommandLine.NamingConventionBinder/ServiceProvider.cs @@ -18,7 +18,7 @@ internal ServiceProvider(BindingContext bindingContext) { [typeof(ParseResult)] = _ => bindingContext.ParseResult, [typeof(IConsole)] = _ => bindingContext.Console, - [typeof(HelpBuilder)] = _ => bindingContext.ParseResult.Configuration.HelpBuilderFactory(bindingContext), + [typeof(HelpBuilder)] = _ => bindingContext.ParseResult.Configuration.HelpBuilderFactory(bindingContext.InvocationContext), [typeof(BindingContext)] = _ => bindingContext }; } diff --git a/src/System.CommandLine/Binding/ServiceProviderValueSource.cs b/src/System.CommandLine.NamingConventionBinder/ServiceProviderValueSource.cs similarity index 100% rename from src/System.CommandLine/Binding/ServiceProviderValueSource.cs rename to src/System.CommandLine.NamingConventionBinder/ServiceProviderValueSource.cs diff --git a/src/System.CommandLine.NamingConventionBinder/System.CommandLine.NamingConventionBinder.csproj b/src/System.CommandLine.NamingConventionBinder/System.CommandLine.NamingConventionBinder.csproj index 3e9813d5f8..cf80841f38 100644 --- a/src/System.CommandLine.NamingConventionBinder/System.CommandLine.NamingConventionBinder.csproj +++ b/src/System.CommandLine.NamingConventionBinder/System.CommandLine.NamingConventionBinder.csproj @@ -1,4 +1,4 @@ - + true @@ -14,10 +14,6 @@ portable - - - - diff --git a/src/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs b/src/System.CommandLine.NamingConventionBinder/ValueDescriptorDefaultValueSource.cs similarity index 100% rename from src/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs rename to src/System.CommandLine.NamingConventionBinder/ValueDescriptorDefaultValueSource.cs diff --git a/src/System.CommandLine.Rendering.Tests/ViewRenderingTests.cs b/src/System.CommandLine.Rendering.Tests/ViewRenderingTests.cs index b3d004b58b..5dfc3e55ea 100644 --- a/src/System.CommandLine.Rendering.Tests/ViewRenderingTests.cs +++ b/src/System.CommandLine.Rendering.Tests/ViewRenderingTests.cs @@ -17,28 +17,18 @@ public class ViewRenderingTests private readonly TestTerminal _terminal = new(); [Fact] - public void Views_can_be_registered_for_specific_types() + public void Views_can_be_used_for_specific_types() { ParseResult parseResult = null; - var command = new RootCommand + var command = new RootCommand(); + command.SetHandler(ctx => { - Handler = CommandHandler.Create( - (r, c) => - { - parseResult = r; - c.Append(new ParseResultView(r)); - }) - }; + parseResult = ctx.ParseResult; + ctx.Console.Append(new ParseResultView(parseResult)); + }); - var config = new CommandLineBuilder(command) - .AddMiddleware(c => - { - c.BindingContext - .AddService( - s => new ParseResultView(s.GetService())); - }) - .Build(); + var config = new CommandLineBuilder(command).Build(); var terminal = new TestTerminal { diff --git a/src/System.CommandLine/Builder/CommandLineBuilder.cs b/src/System.CommandLine/Builder/CommandLineBuilder.cs index 1941badfce..4c600066ad 100644 --- a/src/System.CommandLine/Builder/CommandLineBuilder.cs +++ b/src/System.CommandLine/Builder/CommandLineBuilder.cs @@ -36,7 +36,7 @@ public partial class CommandLineBuilder // that is why we don't use List for middleware private List>? _middlewareList; private Action? _customizeHelpBuilder; - private Func? _helpBuilderFactory; + private Func? _helpBuilderFactory; /// The root command of the application. public CommandLineBuilder(Command rootCommand) @@ -52,18 +52,18 @@ public CommandLineBuilder(Command rootCommand) internal void CustomizeHelpLayout(Action customize) => _customizeHelpBuilder = customize; - internal void UseHelpBuilderFactory(Func factory) => + internal void UseHelpBuilderFactory(Func factory) => _helpBuilderFactory = factory; - private Func GetHelpBuilderFactory() + private Func GetHelpBuilderFactory() { return CreateHelpBuilder; - HelpBuilder CreateHelpBuilder(BindingContext bindingContext) + HelpBuilder CreateHelpBuilder(InvocationContext invocationContext) { var helpBuilder = _helpBuilderFactory is { } - ? _helpBuilderFactory(bindingContext) - : CommandLineConfiguration.DefaultHelpBuilderFactory(bindingContext, MaxHelpWidth); + ? _helpBuilderFactory(invocationContext) + : CommandLineConfiguration.DefaultHelpBuilderFactory(invocationContext, MaxHelpWidth); helpBuilder.OnCustomize = _customizeHelpBuilder; diff --git a/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs b/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs index 211a97d09d..94e593c00f 100644 --- a/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs +++ b/src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs @@ -252,7 +252,7 @@ internal CommandLineBuilder UseHelp(HelpOption helpOption, int? maxWidth = null) /// A delegate that returns an instance of /// The reference to this instance. public CommandLineBuilder UseHelpBuilder( - Func getHelpBuilder) + Func getHelpBuilder) { UseHelpBuilderFactory(getHelpBuilder); diff --git a/src/System.CommandLine/CommandLineConfiguration.cs b/src/System.CommandLine/CommandLineConfiguration.cs index efd791aa35..8d8fb8154c 100644 --- a/src/System.CommandLine/CommandLineConfiguration.cs +++ b/src/System.CommandLine/CommandLineConfiguration.cs @@ -37,7 +37,7 @@ public class CommandLineConfiguration internal readonly IReadOnlyList Middleware; - private Func? _helpBuilderFactory; + private Func? _helpBuilderFactory; private TryReplaceToken? _tokenReplacer; /// @@ -54,7 +54,7 @@ public CommandLineConfiguration( bool enablePosixBundling = true, bool enableTokenReplacement = true, IReadOnlyList? middlewarePipeline = null, - Func? helpBuilderFactory = null, + Func? helpBuilderFactory = null, TryReplaceToken? tokenReplacer = null) : this( command, @@ -80,7 +80,7 @@ internal CommandLineConfiguration( int maxLevenshteinDistance, TimeSpan? processTerminationTimeout, IReadOnlyList? middlewarePipeline, - Func? helpBuilderFactory, + Func? helpBuilderFactory, TryReplaceToken? tokenReplacer, Action? exceptionHandler) { @@ -100,7 +100,7 @@ internal CommandLineConfiguration( public static CommandLineBuilder CreateBuilder(Command rootCommand) => new CommandLineBuilder(rootCommand); - internal static HelpBuilder DefaultHelpBuilderFactory(BindingContext context, int? requestedMaxWidth = null) + internal static HelpBuilder DefaultHelpBuilderFactory(InvocationContext context, int? requestedMaxWidth = null) { int maxWidth = requestedMaxWidth ?? int.MaxValue; if (requestedMaxWidth is null && context.Console is SystemConsole systemConsole) @@ -132,7 +132,7 @@ internal static HelpBuilder DefaultHelpBuilderFactory(BindingContext context, in /// public bool EnableTokenReplacement { get; } - internal Func HelpBuilderFactory => _helpBuilderFactory ??= context => DefaultHelpBuilderFactory(context); + internal Func HelpBuilderFactory => _helpBuilderFactory ??= context => DefaultHelpBuilderFactory(context); internal TryReplaceToken? TokenReplacer => EnableTokenReplacement diff --git a/src/System.CommandLine/Invocation/InvocationContext.cs b/src/System.CommandLine/Invocation/InvocationContext.cs index 03de4d652f..90edfdd009 100644 --- a/src/System.CommandLine/Invocation/InvocationContext.cs +++ b/src/System.CommandLine/Invocation/InvocationContext.cs @@ -1,10 +1,8 @@ // Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.CommandLine.Binding; using System.CommandLine.Help; using System.CommandLine.IO; -using System.CommandLine.Parsing; namespace System.CommandLine.Invocation { @@ -14,7 +12,6 @@ namespace System.CommandLine.Invocation public sealed class InvocationContext { private HelpBuilder? _helpBuilder; - private BindingContext? _bindingContext; private IConsole? _console; /// The result of the current parse operation. @@ -25,11 +22,6 @@ public InvocationContext(ParseResult parseResult, IConsole? console = null) _console = console; } - /// - /// The binding context for the current invocation. - /// - public BindingContext BindingContext => _bindingContext ??= new BindingContext(this); - /// /// The console to which output should be written during the current invocation. /// @@ -42,7 +34,7 @@ public IConsole Console /// /// Enables writing help output. /// - public HelpBuilder HelpBuilder => _helpBuilder ??= ParseResult.Configuration.HelpBuilderFactory(BindingContext); + public HelpBuilder HelpBuilder => _helpBuilder ??= ParseResult.Configuration.HelpBuilderFactory(this); /// /// The parse result for the current invocation.