Skip to content

Commit f30f420

Browse files
Added IConfigurationHelper interface to dynamically choose the method to call given arguments.
1 parent 3b804aa commit f30f420

File tree

8 files changed

+343
-151
lines changed

8 files changed

+343
-151
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// -------------------------------------------------------------------------------------------------
2+
// Copyright (c) almostchristian. All rights reserved.
3+
// -------------------------------------------------------------------------------------------------
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
9+
namespace ConfigurationProcessor
10+
{
11+
/// <summary>
12+
/// Represents a configuration helper for dynamically executing methods.
13+
/// </summary>
14+
public interface IConfigurationProcessor
15+
{
16+
/// <summary>
17+
/// Invokes a specificed configuration method with specificed arguments. Method is chosen based on the argument types.
18+
/// </summary>
19+
/// <typeparam name="T"></typeparam>
20+
/// <param name="instance"></param>
21+
/// <param name="methodName"></param>
22+
/// <param name="arguments"></param>
23+
void Invoke<T>(T instance, string methodName, params object[] arguments)
24+
where T : class;
25+
}
26+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// -------------------------------------------------------------------------------------------------
2+
// Copyright (c) almostchristian. All rights reserved.
3+
// -------------------------------------------------------------------------------------------------
4+
5+
using System;
6+
using System.Linq;
7+
using System.Reflection;
8+
using Microsoft.Extensions.Configuration;
9+
10+
namespace ConfigurationProcessor.Core.Implementation
11+
{
12+
internal class ConfigurationHelperImplementation : IConfigurationProcessor
13+
{
14+
private readonly ResolutionContext resolutionContext;
15+
private readonly IConfigurationSection configurationSection;
16+
private readonly ConfigurationReaderOptions? options;
17+
18+
public ConfigurationHelperImplementation(ResolutionContext resolutionContext, IConfigurationSection configurationSection, ConfigurationReaderOptions? options)
19+
{
20+
this.resolutionContext = resolutionContext;
21+
this.configurationSection = configurationSection;
22+
this.options = options;
23+
}
24+
25+
public void Invoke<T>(T instance, string methodName, params object[] arguments)
26+
where T : class
27+
{
28+
resolutionContext.CallConfigurationMethod(
29+
typeof(T),
30+
methodName,
31+
configurationSection,
32+
null,
33+
Array.Empty<TypeResolver>(),
34+
null!,
35+
() => arguments.ToList(),
36+
(arguments, methodInfo) =>
37+
{
38+
if (methodInfo.IsStatic)
39+
{
40+
arguments.Insert(0, instance);
41+
methodInfo.Invoke(null, arguments.ToArray());
42+
}
43+
else
44+
{
45+
methodInfo.Invoke(instance, arguments.ToArray());
46+
}
47+
});
48+
}
49+
}
50+
}

src/ConfigurationProcessor.Core/Implementation/ConfigurationReader{TConfig}.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ public void AddServices(TConfig builder, string? sectionName, bool getChildren,
2323
var builderDirective = string.IsNullOrEmpty(sectionName) ? ConfigurationSection : ConfigurationSection.GetSection(sectionName);
2424
if (!getChildren || builderDirective.GetChildren().Any())
2525
{
26-
var methodCalls = ResolutionContext.GetMethodCalls(builderDirective, getChildren);
2726
ResolutionContext.CallConfigurationMethods(
2827
typeof(TConfig),
29-
methodCalls,
28+
builderDirective,
29+
getChildren,
30+
null,
3031
options.MethodFilterFactory,
3132
(arguments, methodInfo) =>
3233
{

src/ConfigurationProcessor.Core/Implementation/Extensions.cs

Lines changed: 208 additions & 148 deletions
Large diffs are not rendered by default.

src/Directory.Build.props

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
</PropertyGroup>
66

77
<PropertyGroup>
8-
<Version>1.5.1</Version>
8+
<Version>1.6.0</Version>
99
<FileVersion>$(Version).$([System.DateTime]::Now.ToString(yy))$([System.DateTime]::Now.DayOfYear.ToString(000))</FileVersion>
1010
<PackageVersion>$(Version)</PackageVersion>
1111
<InformationalVersion>$(FileVersion)-$(GIT_VERSION)</InformationalVersion>
@@ -23,6 +23,8 @@
2323
<PackageTags>dependencyinjection;configuration;ioc;di;</PackageTags>
2424
<PackageReadmeFile>README.md</PackageReadmeFile>
2525
<PackageReleaseNotes>
26+
v1.6.0
27+
- Added IConfigurationProcessor interface to dynamically call methods
2628
v1.5.1
2729
- Fixed exception with optional parameters
2830
v1.5.0

tests/ConfigurationProcessor.DependencyInjection.UnitTests/ConfigurationBuilderTestsBase.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,6 +1283,42 @@ public void WithObjectNotation_CallExtensionMethodOnConfigurationObject_Executes
12831283
Assert.Equal("helloworld2314", option.Value.Name);
12841284
}
12851285

1286+
[Fact]
1287+
public void WithObjectNotation_UsingHelper_CallsDynamicAddConfigureName()
1288+
{
1289+
var randomValue = Guid.NewGuid().ToString();
1290+
var json = @$"
1291+
{{
1292+
'WithHelper': '{randomValue}'
1293+
}}";
1294+
1295+
var sp = BuildFromJson(json);
1296+
var option = sp.GetService<IOptions<ComplexObject>>();
1297+
1298+
Assert.NotNull(option);
1299+
Assert.Equal(randomValue, option.Value.Name);
1300+
}
1301+
1302+
[Theory]
1303+
[InlineData("Time")]
1304+
[InlineData("Time2")]
1305+
public void WithObjectNotation_UsingHelperWithComplexOptions_CallsDynamicAddConfigureName(string timeProperty)
1306+
{
1307+
var randomValue = Guid.NewGuid().ToString();
1308+
var json = @$"
1309+
{{
1310+
'WithHelper': {{
1311+
'{timeProperty}' : '13:00:10'
1312+
}}
1313+
}}";
1314+
1315+
var sp = BuildFromJson(json);
1316+
var option = sp.GetService<IOptions<ComplexObject>>();
1317+
1318+
Assert.NotNull(option);
1319+
Assert.Equal(new TimeSpan(13, 0, 10), option.Value.Value.Time);
1320+
}
1321+
12861322
private IServiceProvider BuildFromJson(string json)
12871323
{
12881324
var serviceCollection = ProcessJson(json);

tests/TestDummies/DummyServiceCollectionExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright (c) Integrated Health Information Systems Pte Ltd. All rights reserved.
33
// -------------------------------------------------------------------------------------------------
44

5+
using ConfigurationProcessor;
56
using Microsoft.Extensions.Configuration;
67
using Microsoft.Extensions.DependencyInjection;
78
using System;
@@ -275,5 +276,17 @@ public static void Append<T>(this ComplexObject obj, string value)
275276
{
276277
obj.Name += value;
277278
}
279+
280+
public static IServiceCollection AddWithHelper(this IServiceCollection services, string text, IConfigurationProcessor helper)
281+
{
282+
services.AddConfigurationAction(c => helper.Invoke(c, "AddConfigureName", text));
283+
return services;
284+
}
285+
286+
public static IServiceCollection AddWithHelper(this IServiceCollection services, Action<ComplexObject.ChildValue> configure, IConfigurationProcessor helper)
287+
{
288+
services.AddConfigurationAction(c => helper.Invoke(c, "AddConfigureValue", configure));
289+
return services;
290+
}
278291
}
279292
}

tests/TestDummies/TestDummies.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,8 @@
1212
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
1313
</ItemGroup>
1414

15+
<ItemGroup>
16+
<ProjectReference Include="..\..\src\ConfigurationProcessor.Core\ConfigurationProcessor.Core.csproj" />
17+
</ItemGroup>
18+
1519
</Project>

0 commit comments

Comments
 (0)