-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
95e97fa
commit 357321e
Showing
9 changed files
with
226 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
AdvancedSystems.Core.Tests/DependencyInjection/ServiceCollectionExtensions.HelpersTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using System.Collections.Generic; | ||
|
||
using AdvancedSystems.Core.DependencyInjection; | ||
|
||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
|
||
using Xunit; | ||
|
||
namespace AdvancedSystems.Core.Tests.DependencyInjection; | ||
|
||
public sealed class ServiceCollectionExtensionsHelperTests | ||
{ | ||
public record MyOptions | ||
{ | ||
public string? ConnectionString { get; set; } | ||
|
||
public string? Port { get; set; } | ||
} | ||
|
||
#region Tests | ||
|
||
/// <summary> | ||
/// Tests that <seealso cref="ServiceCollectionExtensions.TryAddOptions{TOptions}(IServiceCollection, IConfigurationSection)"/> | ||
/// configures options from configuration sections only once. | ||
/// </summary> | ||
[Fact] | ||
public void TestTryAddOptions_FromConfiguration() | ||
{ | ||
// Arrange | ||
var services = new ServiceCollection(); | ||
var expectedOption = new MyOptions | ||
{ | ||
ConnectionString = "localhost", | ||
Port = "443" | ||
}; | ||
|
||
var configurationSection = new ConfigurationBuilder() | ||
.AddInMemoryCollection( | ||
[ | ||
new KeyValuePair<string, string?>($"{nameof(MyOptions)}:{nameof(MyOptions.ConnectionString)}", expectedOption.ConnectionString), | ||
new KeyValuePair<string, string?>($"{nameof(MyOptions)}:{nameof(MyOptions.Port)}", expectedOption.Port), | ||
]) | ||
.Build() | ||
.GetSection(nameof(MyOptions)); | ||
|
||
// Act | ||
services.TryAddOptions<MyOptions>(configurationSection); | ||
services.TryAddOptions<MyOptions>(configurationSection); | ||
var serviceProvider = services.BuildServiceProvider(); | ||
var actualOption = serviceProvider.GetService<IOptions<MyOptions>>(); | ||
var optionsMonitor = serviceProvider.GetRequiredService<IOptionsMonitor<MyOptions>>(); | ||
|
||
// Assert | ||
Assert.Multiple(() => | ||
{ | ||
Assert.NotNull(actualOption); | ||
Assert.Equal(expectedOption.ConnectionString, actualOption.Value.ConnectionString); | ||
Assert.Equal(expectedOption.Port, actualOption.Value.Port); | ||
Assert.Single(services, service => service.ServiceType == typeof(IConfigureOptions<MyOptions>)); | ||
}); | ||
} | ||
|
||
/// <summary> | ||
/// Tests that <seealso cref="ServiceCollectionExtensions.TryAddOptions{TOptions}(IServiceCollection, System.Action{TOptions})"/> | ||
/// configures options from the action builder only once. | ||
/// </summary> | ||
[Fact] | ||
public void TestTryAddOptions_FromActionsBuilder() | ||
{ | ||
// Arrange | ||
var services = new ServiceCollection(); | ||
var expectedOption = new MyOptions | ||
{ | ||
ConnectionString = "localhost", | ||
Port = "443" | ||
}; | ||
int counter = 0; | ||
|
||
// Act | ||
services.TryAddOptions<MyOptions>(options => | ||
{ | ||
counter++; | ||
options.ConnectionString = expectedOption.ConnectionString; | ||
options.Port = expectedOption.Port; | ||
}); | ||
|
||
services.TryAddOptions<MyOptions>(_ => counter++); | ||
services.TryAddOptions<MyOptions>(_ => counter++); | ||
services.TryAddOptions<MyOptions>(_ => counter++); | ||
|
||
var serviceProvider = services.BuildServiceProvider(); | ||
var actualOption = serviceProvider.GetService<IOptions<MyOptions>>(); | ||
|
||
Assert.Multiple(() => | ||
{ | ||
Assert.NotNull(actualOption); | ||
Assert.Equal(1, counter); | ||
Assert.Equal(expectedOption.ConnectionString, actualOption.Value.ConnectionString); | ||
Assert.Equal(expectedOption.Port, actualOption.Value.Port); | ||
}); | ||
} | ||
|
||
#endregion | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
70 changes: 70 additions & 0 deletions
70
AdvancedSystems.Core/DependencyInjection/ServiceCollectionExtensions.Helpers.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using System; | ||
using System.Linq; | ||
|
||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.DependencyInjection.Extensions; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace AdvancedSystems.Core.DependencyInjection; | ||
|
||
public static partial class ServiceCollectionExtensions | ||
{ | ||
/// <summary> | ||
/// Registers and binds <typeparamref name="TOptions"/> to the underlying <paramref name="services"/> collection | ||
/// if it has not already been registered, and binds the options to values from the given <paramref name="configurationSection"/>. | ||
/// </summary> | ||
/// <typeparam name="TOptions"> | ||
/// The type of the options to register and configure. | ||
/// </typeparam> | ||
/// <param name="services"> | ||
/// The service collection containing the service. | ||
/// </param> | ||
/// <param name="configurationSection"> | ||
/// A section of the application configuration. | ||
/// </param> | ||
/// <returns> | ||
/// The value of <paramref name="services"/>. | ||
/// </returns> | ||
public static IServiceCollection TryAddOptions<TOptions>(this IServiceCollection services, IConfigurationSection configurationSection) where TOptions : class | ||
{ | ||
bool hasOptions = services.Any(service => service.ServiceType == typeof(IConfigureOptions<TOptions>)); | ||
|
||
if (!hasOptions) | ||
{ | ||
services.AddOptions<TOptions>() | ||
.Bind(configurationSection) | ||
.ValidateDataAnnotations() | ||
.ValidateOnStart(); | ||
} | ||
|
||
return services; | ||
} | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
/// <typeparam name="TOptions"> | ||
/// The type of the options to register and configure. | ||
/// </typeparam> | ||
/// <param name="services"> | ||
/// The service collection containing the service. | ||
/// </param> | ||
/// <param name="configureOptions"> | ||
/// An action to configure the options of type <typeparamref name="TOptions"/>. | ||
/// </param> | ||
/// <returns> | ||
/// The value of <paramref name="services"/>. | ||
/// </returns> | ||
public static IServiceCollection TryAddOptions<TOptions>(this IServiceCollection services, Action<TOptions> configureOptions) where TOptions : class, new() | ||
{ | ||
services.TryAddSingleton(_ => | ||
{ | ||
var options = new TOptions(); | ||
configureOptions(options); | ||
return Options.Create(options); | ||
}); | ||
|
||
return services; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters