Skip to content

Commit

Permalink
Support Action delegates of any number of parameters.
Browse files Browse the repository at this point in the history
  • Loading branch information
almostchristian committed Nov 13, 2022
1 parent 3bc9621 commit f32f2f8
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 132 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ If the extension method is parameterless, use `true` instead of an object. The c
```

### Action Delegate mapping
ConfigurationProcessor can be used with extension methods that use a generic action delegate of up to 7 argument types. An generic argument type of `System.Object` is not supported.
ConfigurationProcessor can be used with extension methods that use a generic action delegate. Generic arguments type of `System.Object` is not supported.

Given the extension method below:
```csharp
Expand Down Expand Up @@ -126,7 +126,7 @@ The configuration below is equivalent to calling `services.AddMyService(options
```

#### Action delegates with more than one argument
When the action delegates with more than one argument, all matching configuration methods will be called
When the action delegates with more than one argument, all matching configuration methods will be called.

Given the extension method below:
```csharp
Expand Down
21 changes: 6 additions & 15 deletions src/ConfigurationProcessor.Core/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,7 @@ public static TContext ProcessConfiguration<TContext>(
MethodFilterFactory? methodFilterFactory = null,
MethodInfo[]? additionalMethods = null)
where TContext : class
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}

configuration.ProcessConfiguration(
=> configuration.ProcessConfiguration(
context,
options =>
{
Expand All @@ -52,8 +46,6 @@ public static TContext ProcessConfiguration<TContext>(
options.AdditionalMethods = additionalMethods ?? Enumerable.Empty<MethodInfo>();
options.ContextPaths = contextPaths;
});
return context;
}

/// <summary>
/// Processes the configuration.
Expand All @@ -65,21 +57,20 @@ public static TContext ProcessConfiguration<TContext>(
/// <returns>The <paramref name="context"/> object for chaining.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="configuration"/> is null.</exception>
public static TContext ProcessConfiguration<TContext>(
this IConfiguration configuration,
TContext context,
Action<ConfigurationReaderOptions> configureOptions)
where TContext : class
this IConfiguration configuration,
TContext context,
Action<ConfigurationReaderOptions> configureOptions)
where TContext : class
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}

context.AddFromConfiguration(
return context.AddFromConfiguration(
configuration,
AssemblyFinder.Auto(),
configureOptions);
return context;
}

internal static TConfig AddFromConfiguration<TConfig>(
Expand Down
109 changes: 60 additions & 49 deletions src/ConfigurationProcessor.Core/Implementation/Extensions.cs

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</PropertyGroup>

<PropertyGroup>
<Version>1.9.0</Version>
<Version>1.10.0</Version>
<FileVersion>$(Version).$([System.DateTime]::Now.ToString(yy))$([System.DateTime]::Now.DayOfYear.ToString(000))</FileVersion>
<PackageVersion>$(Version)</PackageVersion>
<InformationalVersion>$(FileVersion)-$(GIT_VERSION)</InformationalVersion>
Expand All @@ -23,6 +23,8 @@
<PackageTags>dependencyinjection;configuration;ioc;di;</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageReleaseNotes>
v1.10.0
- Support Action delegates of any number of parameters as configuration targets.
v1.9.0
- Support Action delegates of up to 7 generic arguments as configuration targets.
v1.8.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1378,6 +1378,59 @@ public void WithObjectNotation_CallExtensionForConnectionString_SetsConnectionSt
Assert.Equal(expectedConnectionStringValue, option.Value.Name);
}

[Fact]
public void WithObjectNotation_MultiParameterDelegateWithComplexConfig_SetsValue()
{
var json = @"
{
'MultiParameterDelegate2': {
'ConnectionString' : 'abc',
'MultiConfigureComplex': {
'Name': 'hello',
'Value': {
'Time' : '13:00:10',
'Location': 'http://www.google.com'
}
}
}
}";
var sp = BuildFromJson(json);

var option = sp.GetService<IOptions<ComplexObject>>();

Assert.NotNull(option);
Assert.Equal("hello", option.Value.Name);
Assert.Equal(new TimeSpan(13, 0, 10), option.Value.Value.Time);
Assert.Equal("http://www.google.com/", option.Value.Value.Location.ToString());

var option2 = sp.GetService<IOptions<DbConnection>>();
Assert.Equal("abc", option2.Value.ConnectionString);
}

[Fact]
public void WithObjectNotation_MultiParameterDelegateWithArray_SetsValue()
{
var json = @"
{
'MultiParameterDelegate2': {
'ConnectionString' : 'abc',
'MultiConfigureArray': [
'hello',
'def'
]
}
}";
var sp = BuildFromJson(json);

var option = sp.GetService<IOptions<ComplexObject>>();

Assert.NotNull(option);
Assert.Equal("abchello", option.Value.Name);

var option2 = sp.GetService<IOptions<DbConnection>>();
Assert.Equal("abcdef", option2.Value.ConnectionString);
}

[Fact]
public void WithObjectNotation_MultiParameterDelegateWithValueTupleExtension_SetsValue()
{
Expand Down Expand Up @@ -1407,6 +1460,7 @@ public void WithObjectNotation_MultiParameterDelegateWithValueTupleExtension_Set
[InlineData("MultiParameterDelegate5")]
[InlineData("MultiParameterDelegate6")]
[InlineData("MultiParameterDelegate7")]
[InlineData("MultiParameterDelegate8")]
public void WithObjectNotation_MultiParameterDelegateN_SetsValue(string methodName)
{
var json = @"
Expand Down Expand Up @@ -1439,18 +1493,6 @@ public void WithObjectNotation_MultiParameterDelegateWithUnmatchedMethod_ThrowsM
Assert.Throws<MissingMethodException>(() => BuildFromJson(json));
}

[Fact]
public void WithObjectNotation_MultiParameterDelegate8_ThrowsNotSupportedException()
{
var json = @"
{
'MultiParameterDelegate8': {
'ConnectionString' : 'abc'
}
}";
Assert.Throws<NotSupportedException>(() => BuildFromJson(json));
}

[Fact]
public void WithObjectNotation_MultiParameterDelegateWithObjectParameter_ThrowsNotSupportedException()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,13 @@
// Copyright (c) Integrated Health Information Systems Pte Ltd. All rights reserved.
// -------------------------------------------------------------------------------------------------

using ConfigurationProcessor.Core;
using ConfigurationProcessor.Core.Assemblies;
using ConfigurationProcessor.Core.Implementation;
using ConfigurationProcessor.DependencyInjection.UnitTests.Support;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

/* Unmerged change from project 'ConfigurationProcessor.DependencyInjection.UnitTests (net462)'
Before:
using TestDummies;
After:
using System.Linq;
using System.Reflection;
using TestDummies;
*/

/* Unmerged change from project 'ConfigurationProcessor.DependencyInjection.UnitTests (netcoreapp3.1)'
Before:
using TestDummies;
After:
using System.Linq;
using System.Reflection;
using TestDummies;
*/
using System.Reflection;

namespace ConfigurationProcessor.DependencyInjection.UnitTests
{
Expand All @@ -43,6 +26,36 @@ public ConfigurationReaderTests()
new Core.ConfigurationReaderOptions());
}

[Fact]
public void AddServicesWithContextPaths()
{
var configuration = JsonStringConfigSource.LoadConfiguration(@"
{
'Services': {
'WithChildren': {
'SimpleString': 'helloworld'
}
},
'ComplexObject': true
}");
IServiceCollection serviceCollection = new ServiceCollection();
configuration.ProcessConfiguration(serviceCollection, "Services", contextPaths: new string[] { "^ComplexObject", "WithChildren" });

Assert.Collection(
serviceCollection,
sd =>
{
Assert.Equal(typeof(ComplexObject), sd.ServiceType);
var config = Assert.IsType<ComplexObject>(sd.ImplementationInstance);
},
sd =>
{
Assert.Equal(typeof(SimpleValue<string>), sd.ServiceType);
var val = Assert.IsType<SimpleValue<string>>(sd.ImplementationInstance);
Assert.Equal("helloworld", val.Value);
});
}

[Fact]
public void AddServicesSupportExpandedSyntaxWithoutArgs()
{
Expand All @@ -53,7 +66,7 @@ public void AddServicesSupportExpandedSyntaxWithoutArgs()
}]
}";

var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "Services"));
var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadConfigurationSection(json, "Services"));

Assert.Collection(
result,
Expand All @@ -70,7 +83,7 @@ public void AddServicesSupportAlternateSyntaxWithoutArgs()
}
}";

var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "Services"));
var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadConfigurationSection(json, "Services"));

Assert.Collection(
result,
Expand All @@ -90,7 +103,7 @@ public void AddServicesSupportExpandedSyntaxWithArgs()
}]
}";

var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "Services"));
var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadConfigurationSection(json, "Services"));

Assert.Collection(
result,
Expand Down Expand Up @@ -123,7 +136,7 @@ public void AddServicesSupportAlternateSyntaxWithArgs()
}
}";

var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadSection(json, "Services"));
var result = configurationReader.GetMethodCalls(JsonStringConfigSource.LoadConfigurationSection(json, "Services"));

Assert.Collection(
result,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ public JsonStringConfigSource(string json)
}

public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new JsonStringConfigProvider(json);
}
=> new JsonStringConfigProvider(json);

public static IConfigurationSection LoadSection(string json, string section)
{
return new ConfigurationBuilder().Add(new JsonStringConfigSource(json)).Build().GetSection(section);
}
public static IConfiguration LoadConfiguration(string json)
=> new ConfigurationBuilder().Add(new JsonStringConfigSource(json)).Build();

public static IConfigurationSection LoadConfigurationSection(string json, string section)
=> LoadConfiguration(json).GetSection(section);

public static IDictionary<string, string> LoadData(string json)
{
Expand Down
Loading

0 comments on commit f32f2f8

Please sign in to comment.