Skip to content

Commit 51997d7

Browse files
committed
Fix #85 - lower priority of resolving AdditionalServices after most built-in services
1 parent 0c26dde commit 51997d7

File tree

3 files changed

+54
-14
lines changed

3 files changed

+54
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Bug fixes:
66

77
- Don't assign option and argument options if no value was provided, preserving the default CLR value unless there is user-input.
88
- Fix ShowHint() to use ShortName or SymbolName if OptionHelp.LongName is not set
9+
- Fix [#85](https://github.com/natemcmaster/CommandLineUtils/issues/85) - lower priority of resolving AdditionalServices after most built-in services
910

1011
Minor improvements:
1112

src/CommandLineUtils/CommandLineApplication.cs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -922,20 +922,8 @@ public object GetService(Type serviceType)
922922
return _parent;
923923
}
924924

925-
if (_parent.AdditionalServices != null)
926-
{
927-
var retVal = _parent.AdditionalServices.GetService(serviceType);
928-
if (retVal != null)
929-
{
930-
return retVal;
931-
}
932-
}
933-
934-
if (serviceType == typeof(IConsole))
935-
{
936-
return _parent._context.Console;
937-
}
938-
925+
// prefer this type before AdditionalServces because it is common for service containers to automatically
926+
// create IEnumerable<T> to allow registration of multiple services
939927
if (serviceType == typeof(IEnumerable<CommandOption>))
940928
{
941929
return _parent.GetOptions();
@@ -961,6 +949,22 @@ public object GetService(Type serviceType)
961949
return accessor.GetModel();
962950
}
963951

952+
if (_parent.AdditionalServices != null)
953+
{
954+
var retVal = _parent.AdditionalServices.GetService(serviceType);
955+
if (retVal != null)
956+
{
957+
return retVal;
958+
}
959+
}
960+
961+
// Resolve this after AdditionalServices to support overriding IConsole from a custom service container
962+
// may be overridden
963+
if (serviceType == typeof(IConsole))
964+
{
965+
return _parent._context.Console;
966+
}
967+
964968
return null;
965969
}
966970
}

test/CommandLineUtils.Tests/ConstructorInjectionConventionTests.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Collections.Generic;
6+
using System.Linq;
67
using Microsoft.Extensions.DependencyInjection;
78
using Xunit;
89
using Xunit.Abstractions;
@@ -50,6 +51,40 @@ public void ItSupportsCustomServices()
5051
Assert.Same(testConsole, app.Model.Console);
5152
}
5253

54+
private class OptionsCtorCommand
55+
{
56+
private readonly IEnumerable<CommandOption> _options;
57+
private readonly IEnumerable<CommandArgument> _arguments;
58+
59+
public OptionsCtorCommand(IEnumerable<CommandOption> options, IEnumerable<CommandArgument> arguments)
60+
{
61+
_options = options;
62+
_arguments = arguments;
63+
}
64+
65+
public int GetOptionCount() => _options.Count();
66+
public int GetArgCount() => _arguments.Count();
67+
68+
[Option]
69+
public string Opt { get; }
70+
71+
[Argument(0)]
72+
public string Arg { get; }
73+
}
74+
75+
[Fact]
76+
public void ItPrefersIEnumOfOptionsFromUs()
77+
{
78+
var app = new CommandLineApplication<OptionsCtorCommand>();
79+
var services = new ServiceCollection().BuildServiceProvider();
80+
app.Conventions.UseDefaultConventions().UseConstructorInjection(services);
81+
app.Parse();
82+
Assert.Empty(services.GetServices<IEnumerable<CommandOption>>());
83+
Assert.Empty(services.GetServices<IEnumerable<CommandArgument>>());
84+
Assert.Equal(1, app.Model.GetOptionCount());
85+
Assert.Equal(1, app.Model.GetArgCount());
86+
}
87+
5388
[Subcommand("test", typeof(Child))]
5489
private class Parent
5590
{

0 commit comments

Comments
 (0)