diff --git a/src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs b/src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs index ab446b2d9c..c493c93fbf 100644 --- a/src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs +++ b/src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs @@ -113,6 +113,50 @@ public static async Task Can_bind_to_arguments_via_injection() service.StringValue.Should().Be("TEST"); } + [Fact] + public static async Task Invokes_DerivedClass() + { + var service = new MyService(); + + var cmd = new RootCommand(); + cmd.AddCommand(new MyCommand()); + cmd.AddCommand(new MyOtherCommand()); + var parser = new CommandLineBuilder(cmd) + .UseHost((builder) => { + builder.ConfigureServices(services => + { + services.AddTransient(x => service); + }) + .UseCommandHandler() + .UseCommandHandler(); + }) + .Build(); + + await parser.InvokeAsync(new string[] { "mycommand", "--int-option", "54" }); + service.Value.Should().Be(54); + + await parser.InvokeAsync(new string[] { "myothercommand", "TEST" }); + service.StringValue.Should().Be("TEST"); + } + + public abstract class MyBaseHandler : ICommandHandler + { + public int IntOption { get; set; } // bound from option + public IConsole Console { get; set; } // bound from DI + + public int Invoke(InvocationContext context) + { + return Act(); + } + + public Task InvokeAsync(InvocationContext context) + { + return Task.FromResult(Act()); + } + + protected abstract int Act(); + } + public class MyCommand : Command { public MyCommand() : base(name: "mycommand") @@ -144,6 +188,22 @@ public Task InvokeAsync(InvocationContext context) return Task.FromResult(IntOption); } } + + public class MyDerivedHandler : MyBaseHandler + { + private readonly MyService service; + + public MyDerivedHandler(MyService service) + { + this.service = service; + } + + protected override int Act() + { + service.Value = IntOption; + return IntOption; + } + } } public class MyOtherCommand : Command @@ -177,6 +237,25 @@ public Task InvokeAsync(InvocationContext context) return Task.FromResult(service.Action?.Invoke() ?? 0); } } + + public class MyDerivedHandler : MyBaseHandler + { + private readonly MyService service; + + public MyDerivedHandler(MyService service) + { + this.service = service; + } + + public string One { get; set; } + + protected override int Act() + { + service.Value = IntOption; + service.StringValue = One; + return service.Action?.Invoke() ?? 0; + } + } } public class MyService diff --git a/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs b/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs index c41ecb2502..4c71e390ac 100644 --- a/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs +++ b/src/System.CommandLine.NamingConventionBinder/MethodInfoHandlerDescriptor.cs @@ -40,7 +40,7 @@ public override ICommandHandler GetCommandHandler() } } - public override ModelDescriptor Parent => ModelDescriptor.FromType(_handlerMethodInfo.DeclaringType); + public override ModelDescriptor Parent => ModelDescriptor.FromType(_handlerMethodInfo.ReflectedType); private protected override IEnumerable InitializeParameterDescriptors() => _handlerMethodInfo.GetParameters() diff --git a/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs b/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs index 05ca904a33..72a53338f6 100644 --- a/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs +++ b/src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs @@ -73,7 +73,7 @@ public async Task InvokeAsync(InvocationContext context) if (_handlerDelegate is null) { var invocationTarget = _invocationTarget ?? - bindingContext.GetService(_handlerMethodInfo!.DeclaringType); + bindingContext.GetService(_handlerMethodInfo!.ReflectedType); if(invocationTarget is { }) { _invocationTargetBinder?.UpdateInstance(invocationTarget, bindingContext);