From 4e06c9f5ac0cbc972b68eae1fb01b6c5b24e6b3f Mon Sep 17 00:00:00 2001 From: Chee Kent Yong Date: Fri, 20 Dec 2019 13:26:29 +0100 Subject: [PATCH 1/4] Added support for configuring options through an Action parameter --- Readme.md | 16 +++++++++ .../ServiceCollectionExtensions.cs | 17 ++++++++-- .../ConfigureTests.cs | 30 +++++++++++++++++ .../Helpers/TestHelpers.cs | 33 ++++++++++++++----- 4 files changed, 85 insertions(+), 11 deletions(-) create mode 100644 tests/Rtl.Configuration.Validation.Tests/ConfigureTests.cs diff --git a/Readme.md b/Readme.md index 1b3e2a3..072418b 100644 --- a/Readme.md +++ b/Readme.md @@ -69,3 +69,19 @@ public static T GetConfig(this IConfiguration configuration, string sectionNa ``` Gets config of type `T` from configuration, validates and returns it. Use this method when you don't need to add IOptions and you want to get validated config inside `ConfigureServices` method and use right away + +#### Configure +```csharp +public static IServiceCollection Configure(this IServiceCollection services, Action configure) + where T : class, new() +``` +Supports configuring your service through the provision of an `Action` parameter. + +Example usage: +```csharp +services.Configure(options => configuration.Bind(options)); +``` +Or: +```csharp +services.Configure(options => options.BaseAddress = new Uri("http://localhost:443")) +``` \ No newline at end of file diff --git a/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs b/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs index 23caeed..163a6b2 100644 --- a/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs +++ b/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -8,7 +9,8 @@ namespace Rtl.Configuration.Validation { public static class ServiceCollectionExtensions { - public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration configuration, string sectionName) + public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration configuration, + string sectionName) where T : class, new() { return services.AddConfig(configuration.GetSection(sectionName)); @@ -16,6 +18,15 @@ public static IServiceCollection AddConfig(this IServiceCollection services, public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration configuration) where T : class, new() + { + services.ConfigureWithValidation(options => configuration.Bind(options)); + + return services; + } + + public static IServiceCollection ConfigureWithValidation(this IServiceCollection services, + Action configure) + where T : class, new() { if (services.Any(x => x.ServiceType == typeof(IConfigureOptions))) { @@ -27,7 +38,7 @@ public static IServiceCollection AddConfig(this IServiceCollection services, services.AddTransient(); } - services.Configure(configuration); + services.Configure(configure); services.AddTransient>(); return services; diff --git a/tests/Rtl.Configuration.Validation.Tests/ConfigureTests.cs b/tests/Rtl.Configuration.Validation.Tests/ConfigureTests.cs new file mode 100644 index 0000000..eab1f97 --- /dev/null +++ b/tests/Rtl.Configuration.Validation.Tests/ConfigureTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Threading.Tasks; +using Rtl.Configuration.Validation.Tests.Configs; +using Rtl.Configuration.Validation.Tests.Helpers; +using Xunit; + +namespace Rtl.Configuration.Validation.Tests +{ + public class ConfigureTests + { + [Fact] + public async Task ConfigureServicesDoesntThrow() + { + await TestHelpers.ValidationSucceeds(null, services => + services.ConfigureWithValidation(option => + { + option.Name = "asd"; + option.Value = 5; + })); + } + + [Fact] + public void ConfigureServicesThrows() + { + TestHelpers.ValidationThrows(null, services => + services.ConfigureWithValidation(option => + option.Name = string.Empty)); + } + } +} \ No newline at end of file diff --git a/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs b/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs index 5e0ce02..387ccad 100644 --- a/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs +++ b/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs @@ -6,6 +6,7 @@ using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Rtl.Configuration.Validation.Tests.Helpers @@ -15,19 +16,26 @@ static class TestHelpers public static void ValidationThrows(Dictionary settings, string sectionName = "test") where TConfig : class, new() { - IConfiguration configuration = null; + IConfiguration configuration = new ConfigurationBuilder() + .AddInMemoryCollection(settings) + .Build(); + ValidationThrows(settings, services => services.AddConfig(configuration, sectionName)); + } + + public static void ValidationThrows(Dictionary settings, + Action configure) + { Assert.Throws(() => { var webHost = WebHost.CreateDefaultBuilder() .ConfigureAppConfiguration((hostingContext, config) => { config.AddInMemoryCollection(settings); - configuration = config.Build(); }) .ConfigureServices(services => { - services.AddConfig(configuration, sectionName); + configure(services); }) .Configure(app => { @@ -40,21 +48,30 @@ public static void ValidationThrows(Dictionary settings }); } - public static async Task ValidationSucceeds(Dictionary settings, string sectionName = "test") + public static Task ValidationSucceeds(Dictionary settings, + string sectionName = "test") where TConfig : class, new() { - IConfiguration configuration = null; + IConfiguration configuration = new ConfigurationBuilder() + .AddInMemoryCollection(settings) + .Build(); + + return ValidationSucceeds(settings, services => services.AddConfig(configuration, sectionName)); + } + + public static async Task ValidationSucceeds(Dictionary settings, + Action configure) + { using (var cts = new CancellationTokenSource()) { var webHost = WebHost.CreateDefaultBuilder() .ConfigureAppConfiguration((hostingContext, config) => { config.AddInMemoryCollection(settings); - configuration = config.Build(); }) .ConfigureServices(services => { - services.AddConfig(configuration, sectionName); + configure(services); }) .Configure(app => { @@ -67,4 +84,4 @@ public static async Task ValidationSucceeds(Dictionary } } } -} +} \ No newline at end of file From 7a537b9ac52e81a047fd621a3e2f82db6c8c0dbe Mon Sep 17 00:00:00 2001 From: Chee Kent Yong Date: Fri, 20 Dec 2019 13:40:50 +0100 Subject: [PATCH 2/4] Fix methods that were broken up due to IDE --- .../ServiceCollectionExtensions.cs | 6 ++---- .../Helpers/TestHelpers.cs | 9 +++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs b/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs index 163a6b2..3931ed7 100644 --- a/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs +++ b/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs @@ -9,8 +9,7 @@ namespace Rtl.Configuration.Validation { public static class ServiceCollectionExtensions { - public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration configuration, - string sectionName) + public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration configuration, string sectionName) where T : class, new() { return services.AddConfig(configuration.GetSection(sectionName)); @@ -24,8 +23,7 @@ public static IServiceCollection AddConfig(this IServiceCollection services, return services; } - public static IServiceCollection ConfigureWithValidation(this IServiceCollection services, - Action configure) + public static IServiceCollection ConfigureWithValidation(this IServiceCollection services, Action configure) where T : class, new() { if (services.Any(x => x.ServiceType == typeof(IConfigureOptions))) diff --git a/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs b/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs index 387ccad..6da9614 100644 --- a/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs +++ b/tests/Rtl.Configuration.Validation.Tests/Helpers/TestHelpers.cs @@ -23,8 +23,7 @@ public static void ValidationThrows(Dictionary settings ValidationThrows(settings, services => services.AddConfig(configuration, sectionName)); } - public static void ValidationThrows(Dictionary settings, - Action configure) + public static void ValidationThrows(Dictionary settings, Action configure) { Assert.Throws(() => { @@ -48,8 +47,7 @@ public static void ValidationThrows(Dictionary settings, }); } - public static Task ValidationSucceeds(Dictionary settings, - string sectionName = "test") + public static Task ValidationSucceeds(Dictionary settings, string sectionName = "test") where TConfig : class, new() { IConfiguration configuration = new ConfigurationBuilder() @@ -59,8 +57,7 @@ public static Task ValidationSucceeds(Dictionary settin return ValidationSucceeds(settings, services => services.AddConfig(configuration, sectionName)); } - public static async Task ValidationSucceeds(Dictionary settings, - Action configure) + public static async Task ValidationSucceeds(Dictionary settings, Action configure) { using (var cts = new CancellationTokenSource()) { From a758e14920ee22d319d965464fc4edcb7d7dcfd6 Mon Sep 17 00:00:00 2001 From: Chee Kent Yong Date: Fri, 20 Dec 2019 13:43:26 +0100 Subject: [PATCH 3/4] Renamed tests to be a bit more consistent with the method naming --- .../{ConfigureTests.cs => ConfigureWithValidationTests.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename tests/Rtl.Configuration.Validation.Tests/{ConfigureTests.cs => ConfigureWithValidationTests.cs} (87%) diff --git a/tests/Rtl.Configuration.Validation.Tests/ConfigureTests.cs b/tests/Rtl.Configuration.Validation.Tests/ConfigureWithValidationTests.cs similarity index 87% rename from tests/Rtl.Configuration.Validation.Tests/ConfigureTests.cs rename to tests/Rtl.Configuration.Validation.Tests/ConfigureWithValidationTests.cs index eab1f97..c2a84fa 100644 --- a/tests/Rtl.Configuration.Validation.Tests/ConfigureTests.cs +++ b/tests/Rtl.Configuration.Validation.Tests/ConfigureWithValidationTests.cs @@ -9,7 +9,7 @@ namespace Rtl.Configuration.Validation.Tests public class ConfigureTests { [Fact] - public async Task ConfigureServicesDoesntThrow() + public async Task ConfigureWithValidationDoesntThrow() { await TestHelpers.ValidationSucceeds(null, services => services.ConfigureWithValidation(option => @@ -20,7 +20,7 @@ await TestHelpers.ValidationSucceeds(null, services => } [Fact] - public void ConfigureServicesThrows() + public void ConfigureWithValidationThrows() { TestHelpers.ValidationThrows(null, services => services.ConfigureWithValidation(option => From 47adc1e513b2fd5eb872039765c4fb648735417d Mon Sep 17 00:00:00 2001 From: Chee Kent Yong Date: Fri, 20 Dec 2019 13:47:21 +0100 Subject: [PATCH 4/4] Clean up AddConfig in ServiceCollectionExtensions --- .../ServiceCollectionExtensions.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs b/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs index 3931ed7..b768949 100644 --- a/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs +++ b/src/Rtl.Configuration.Validation/ServiceCollectionExtensions.cs @@ -18,9 +18,7 @@ public static IServiceCollection AddConfig(this IServiceCollection services, public static IServiceCollection AddConfig(this IServiceCollection services, IConfiguration configuration) where T : class, new() { - services.ConfigureWithValidation(options => configuration.Bind(options)); - - return services; + return services.ConfigureWithValidation(options => configuration.Bind(options)); } public static IServiceCollection ConfigureWithValidation(this IServiceCollection services, Action configure)