From 5b193880910aeada3e2d2ad5f1fbe7def999568e Mon Sep 17 00:00:00 2001 From: Joshua Harms Date: Tue, 14 May 2024 01:45:56 -0500 Subject: [PATCH] Add new ExponentialRetryPolicy's default options to DI when missing --- .../ServiceCollectionExtensionTests.cs | 59 ++++++++++++++++++- .../ServiceCollectionExtensions.cs | 31 +++++++++- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/ShopifySharp.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionTests.cs b/ShopifySharp.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionTests.cs index 229ce2030..47e2f14c2 100644 --- a/ShopifySharp.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionTests.cs +++ b/ShopifySharp.Extensions.DependencyInjection.Tests/ServiceCollectionExtensionTests.cs @@ -1,5 +1,6 @@ using ShopifySharp.Utilities; using System.Reflection; +using ShopifySharp.Infrastructure.Policies.ExponentialRetry; namespace ShopifySharp.Extensions.DependencyInjection.Tests; @@ -45,6 +46,33 @@ public void AddShopifySharpRequestExecutionPolicy_AllowsAddingMoreThanOnePolicy( .BeOfType(); } + [Fact] + public void AddShopifySharpRequestExecutionPolicy_WhenThePolicyIsExponentialRetry_AddsDefaultOptionsWhenTheyDontAlreadyExist() + { + // Setup + var container = new ServiceCollection(); + + // Act + container.AddShopifySharpRequestExecutionPolicy(); + + // Assert + var serviceProvider = container.BuildServiceProvider(); + var options = serviceProvider.GetService(); + var policy = serviceProvider.GetService(); + + options.Should() + .NotBeNull() + .And + .BeOfType() + .And + .BeEquivalentTo(ExponentialRetryPolicyOptions.Default()); + + policy.Should() + .NotBeNull() + .And + .BeOfType(); + } + [Fact] public void AddShopifySharpUtilities_AddsUtilities() { @@ -149,7 +177,7 @@ public void AddShopifySharpServiceFactories_AddsServiceFactories() } var serviceFactoryTypes = assembly - ?.GetTypes() + .GetTypes() .Where(t => t.IsInterface && t.IsPublic && t.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IServiceFactory<>))) @@ -197,6 +225,33 @@ public void AddShopifySharp_AddsRequestExecutionPolicy_AddsUtilities_ThenAddsSer .BeOfType(); } + [Fact] + public void AddShopifySharp_WhenThePolicyIsExponentialRetry_AddsDefaultOptionsWhenTheyDontAlreadyExist() + { + // Setup + var container = new ServiceCollection(); + + // Act + container.AddShopifySharp(); + + // Assert + var serviceProvider = container.BuildServiceProvider(); + var options = serviceProvider.GetService(); + var policy = serviceProvider.GetService(); + + options.Should() + .NotBeNull() + .And + .BeOfType() + .And + .BeEquivalentTo(ExponentialRetryPolicyOptions.Default()); + + policy.Should() + .NotBeNull() + .And + .BeOfType(); + } + [Theory] [InlineData(ServiceLifetime.Scoped)] [InlineData(ServiceLifetime.Singleton)] @@ -236,4 +291,4 @@ public void AddShopifySharp_AddsRequestExecutionPolicy_AddsUtilities_ThenAddsSer .Should() .NotBeNull(), serviceLifetime); } -} \ No newline at end of file +} diff --git a/ShopifySharp.Extensions.DependencyInjection/ServiceCollectionExtensions.cs b/ShopifySharp.Extensions.DependencyInjection/ServiceCollectionExtensions.cs index 69f8844ba..b6a89c115 100644 --- a/ShopifySharp.Extensions.DependencyInjection/ServiceCollectionExtensions.cs +++ b/ShopifySharp.Extensions.DependencyInjection/ServiceCollectionExtensions.cs @@ -5,6 +5,7 @@ using ShopifySharp.Utilities; using System.Reflection; using System.Linq; +using ShopifySharp.Infrastructure.Policies.ExponentialRetry; // ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedType.Global @@ -25,6 +26,12 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddShopifySharpRequestExecutionPolicy(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IRequestExecutionPolicy { + if (typeof(T) == typeof(ExponentialRetryPolicy)) + { + services.AddImplementationIfNotRegistered( + _ => ExponentialRetryPolicyOptions.Default(), + lifetime); + } services.Add(new ServiceDescriptor(typeof(IRequestExecutionPolicy), typeof(T), lifetime)); return services; } @@ -43,7 +50,7 @@ public static IServiceCollection AddShopifySharpUtilities(this IServiceCollectio { var options = new ShopifySharpUtilityOptions(); configure?.Invoke(options); - + if(options.OauthUtility != null) { services.Add(new ServiceDescriptor(typeof(IShopifyOauthUtility), f => options.OauthUtility, lifetime)); @@ -76,7 +83,7 @@ public static IServiceCollection AddShopifySharpUtilities(this IServiceCollectio /// /// Adds ShopifySharp's service factories to your Dependency Injection container. If you've added an , - /// the service factories will use it when creating ShopifySharp services. + /// the service factories will use it when creating ShopifySharp services. /// /// The lifetime of ShopifySharp's service factories. public static IServiceCollection AddShopifySharpServiceFactories(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) @@ -121,9 +128,29 @@ public static IServiceCollection AddShopifySharpServiceFactories(this IServiceCo public static IServiceCollection AddShopifySharp(this IServiceCollection services, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : class, IRequestExecutionPolicy { + if (typeof(T) == typeof(ExponentialRetryPolicy)) + { + services.AddImplementationIfNotRegistered( + _ => ExponentialRetryPolicyOptions.Default(), + lifetime); + } + return services .AddShopifySharpRequestExecutionPolicy(lifetime: lifetime) .AddShopifySharpUtilities(lifetime: lifetime) .AddShopifySharpServiceFactories(lifetime: lifetime); } + + /// + /// Registers the interface and its implementation if they aren't already registered. + /// + private static void AddImplementationIfNotRegistered(this IServiceCollection services, Func factory, ServiceLifetime lifetime) + where TImplementation : notnull, TService + { + services.TryAdd(new ServiceDescriptor(typeof(TService), (innerServices) => + { + var output = factory.Invoke(innerServices); + return output; + }, lifetime)); + } }