From 5126d1d21948bef4913d2dd278292595bb47298f Mon Sep 17 00:00:00 2001 From: Jens Schulze Date: Mon, 24 Feb 2020 14:50:03 +0100 Subject: [PATCH 1/2] add CtpClientFactory refactor dependency injection to use CtpClientFactory refactor UserAgentProvider to be added at HttpClientConfig --- .../ClientTests.cs | 3 +-- .../MessagesTests.cs | 3 +-- .../commercetools.Sdk.HttpApi/CtpClient.cs | 20 ++------------- .../CtpClientFactory.cs | 25 +++++++++++++++++++ .../DependencyInjectionSetup.cs | 18 ++++++++----- .../ICtpClientFactory.cs | 9 +++++++ .../DependencyInjectionSetup.cs | 17 +++++++++---- 7 files changed, 62 insertions(+), 33 deletions(-) create mode 100644 commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClientFactory.cs create mode 100644 commercetools.Sdk/commercetools.Sdk.HttpApi/ICtpClientFactory.cs diff --git a/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/ClientTests.cs b/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/ClientTests.cs index 011bfc6f..9232ceab 100644 --- a/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/ClientTests.cs +++ b/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/ClientTests.cs @@ -46,8 +46,7 @@ public void GetCategoryById() IClient commerceToolsClient = new CtpClient( mockHttpClientFactory.Object, this.clientFixture.GetService(), - this.clientFixture.GetService(), - this.clientFixture.GetService() + this.clientFixture.GetService() ); string categoryId = "2bafc816-4223-4ff0-ac8a-0f08a8f29fd6"; Category category = commerceToolsClient.ExecuteAsync(new GetByIdCommand(new Guid(categoryId))).Result; diff --git a/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/MessagesTests.cs b/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/MessagesTests.cs index ef7f2ad9..8b9ca5d4 100644 --- a/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/MessagesTests.cs +++ b/commercetools.Sdk/Tests/commercetools.Sdk.HttpApi.Tests/MessagesTests.cs @@ -47,8 +47,7 @@ public void GetMessageByIdForCategoryCreatedAction() IClient commerceToolsClient = new CtpClient( mockHttpClientFactory.Object, this.clientFixture.GetService(), - this.clientFixture.GetService(), - this.clientFixture.GetService() + this.clientFixture.GetService() ); string messageId = "174adf2f-783f-4ce5-a2d5-ee7d3ee7caf4"; CategoryCreatedMessage categoryCreatedMessage = commerceToolsClient.ExecuteAsync(new GetByIdCommand(new Guid(messageId))).Result as CategoryCreatedMessage; diff --git a/commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClient.cs b/commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClient.cs index 47595b35..80002705 100644 --- a/commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClient.cs +++ b/commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClient.cs @@ -3,7 +3,6 @@ using System.Net.Http; using System.Threading.Tasks; using Client; - using DelegatingHandlers; using Domain.Exceptions; using Serialization; @@ -12,36 +11,21 @@ public class CtpClient : IClient private readonly IHttpApiCommandFactory httpApiCommandFactory; private readonly IHttpClientFactory httpClientFactory; private readonly ISerializerService serializerService; - private readonly IUserAgentProvider userAgentProvider; private HttpClient httpClient; public CtpClient( IHttpClientFactory httpClientFactory, IHttpApiCommandFactory httpApiCommandFactory, - ISerializerService serializerService, - IUserAgentProvider userAgentProvider) + ISerializerService serializerService) { this.httpClientFactory = httpClientFactory; this.serializerService = serializerService; this.httpApiCommandFactory = httpApiCommandFactory; - this.userAgentProvider = userAgentProvider; } public string Name { get; set; } = DefaultClientNames.Api; - private HttpClient HttpClient - { - get - { - if (this.httpClient == null) - { - this.httpClient = this.httpClientFactory.CreateClient(this.Name); - this.httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(this.userAgentProvider.UserAgent); - } - - return this.httpClient; - } - } + private HttpClient HttpClient => this.httpClient ?? (this.httpClient = this.httpClientFactory.CreateClient(this.Name)); public async Task ExecuteAsync(Command command) { diff --git a/commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClientFactory.cs b/commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClientFactory.cs new file mode 100644 index 00000000..b41a645d --- /dev/null +++ b/commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClientFactory.cs @@ -0,0 +1,25 @@ +using System.Net.Http; +using commercetools.Sdk.Client; +using commercetools.Sdk.Serialization; + +namespace commercetools.Sdk.HttpApi +{ + public class CtpClientFactory : ICtpClientFactory + { + private readonly IHttpClientFactory clientFactory; + private readonly IHttpApiCommandFactory httpApiCommandFactory; + private readonly ISerializerService serializerService; + + public CtpClientFactory(IHttpClientFactory clientFactory, IHttpApiCommandFactory httpApiCommandFactory, ISerializerService serializerService) + { + this.clientFactory = clientFactory; + this.httpApiCommandFactory = httpApiCommandFactory; + this.serializerService = serializerService; + } + + public IClient Create(string name) + { + return new CtpClient(clientFactory, httpApiCommandFactory, serializerService) { Name = name }; + } + } +} diff --git a/commercetools.Sdk/commercetools.Sdk.HttpApi/DependencyInjectionSetup.cs b/commercetools.Sdk/commercetools.Sdk.HttpApi/DependencyInjectionSetup.cs index c6a031fb..75cede96 100644 --- a/commercetools.Sdk/commercetools.Sdk.HttpApi/DependencyInjectionSetup.cs +++ b/commercetools.Sdk/commercetools.Sdk.HttpApi/DependencyInjectionSetup.cs @@ -24,6 +24,8 @@ public static class DependencyInjectionSetup { public static IDictionary UseHttpApi(this IServiceCollection services, IConfiguration configuration, IDictionary clients) { + services.UseHttpApiDefaults(); + if (clients.Count() == 1) { return services.UseSingleClient(configuration, clients.First().Key, clients.First().Value); @@ -34,7 +36,7 @@ public static IDictionary UseHttpApi(this IServiceCo private static IDictionary UseMultipleClients(this IServiceCollection services, IConfiguration configuration, IDictionary clients) { - services.UseHttpApiDefaults(); + services.AddSingleton(); var builders = new ConcurrentDictionary(); foreach (KeyValuePair client in clients) { @@ -45,7 +47,7 @@ private static IDictionary UseMultipleClients(this I Validator.ValidateObject(clientConfiguration, new ValidationContext(clientConfiguration), true); builders.TryAdd(clientName, services.SetupClient(clientName, clientConfiguration, tokenFlow)); - services.AddSingleton(c => new CtpClient(c.GetService(), c.GetService(), c.GetService(), c.GetService()) { Name = clientName }); + services.AddSingleton(c => c.GetService().Create(clientName)); } return builders; @@ -53,11 +55,11 @@ private static IDictionary UseMultipleClients(this I private static IDictionary UseSingleClient(this IServiceCollection services, IConfiguration configuration, string clientName, TokenFlow tokenFlow) { + services.AddSingleton(); IClientConfiguration clientConfiguration = configuration.GetSection(clientName).Get(); Validator.ValidateObject(clientConfiguration, new ValidationContext(clientConfiguration), true); - services.UseHttpApiDefaults(); - services.AddSingleton(c => new CtpClient(c.GetService(), c.GetService(), c.GetService(), c.GetService()) { Name = clientName }); + services.AddSingleton(c => c.GetService().Create(clientName)); var builders = new ConcurrentDictionary(); builders.TryAdd(clientName, services.SetupClient(clientName, clientConfiguration, tokenFlow)); @@ -68,8 +70,12 @@ private static IDictionary UseSingleClient(this ISer private static IHttpClientBuilder SetupClient(this IServiceCollection services, string clientName, IClientConfiguration clientConfiguration, TokenFlow tokenFlow) { var httpClientBuilder = services.AddHttpClient(clientName) - .ConfigureHttpClient(client => - client.BaseAddress = new Uri(clientConfiguration.ApiBaseAddress + clientConfiguration.ProjectKey + "/")) + .ConfigureHttpClient((c, client) => + { + client.BaseAddress = + new Uri(clientConfiguration.ApiBaseAddress + clientConfiguration.ProjectKey + "/"); + client.DefaultRequestHeaders.UserAgent.ParseAdd(c.GetService().UserAgent); + }) .AddHttpMessageHandler(c => { var providers = c.GetServices(); diff --git a/commercetools.Sdk/commercetools.Sdk.HttpApi/ICtpClientFactory.cs b/commercetools.Sdk/commercetools.Sdk.HttpApi/ICtpClientFactory.cs new file mode 100644 index 00000000..db542345 --- /dev/null +++ b/commercetools.Sdk/commercetools.Sdk.HttpApi/ICtpClientFactory.cs @@ -0,0 +1,9 @@ +using commercetools.Sdk.Client; + +namespace commercetools.Sdk.HttpApi +{ + public interface ICtpClientFactory + { + IClient Create(string name); + } +} \ No newline at end of file diff --git a/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs b/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs index c976fa09..fce0624a 100644 --- a/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs +++ b/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs @@ -143,6 +143,7 @@ private static IDictionary UseMultipleClients(this C { var collection = new ServiceCollection(); services.UseHttpApiDefaults(); + services.Register(() => new CtpClientFactory(collection.BuildServiceProvider().GetService(), services.GetService(), services.GetService()), Lifestyle.Singleton); var builders = new ConcurrentDictionary(); var clientBuilders = new List(); @@ -156,7 +157,7 @@ private static IDictionary UseMultipleClients(this C builders.TryAdd(clientName, services.SetupClient(collection, clientName, clientConfiguration, tokenFlow)); - clientBuilders.Add(Lifestyle.Singleton.CreateRegistration(() => new CtpClient(collection.BuildServiceProvider().GetService(), services.GetService(), services.GetService(), services.GetService()) { Name = clientName }, services)); + clientBuilders.Add(Lifestyle.Singleton.CreateRegistration(() => services.GetService().Create(clientName), services)); } services.RegisterCollection(clientBuilders); @@ -189,6 +190,7 @@ private static IDictionary UseSingleClient(this Cont { var collection = new ServiceCollection(); services.UseHttpApiDefaults(); + services.Register(() => new CtpClientFactory(collection.BuildServiceProvider().GetService(), services.GetService(), services.GetService()), Lifestyle.Singleton); var configurationSection = configuration.GetSection(clientName); IClientConfiguration clientConfiguration = configurationSection.Get(); @@ -196,8 +198,9 @@ private static IDictionary UseSingleClient(this Cont var builders = new ConcurrentDictionary(); builders.TryAdd(clientName, services.SetupClient(collection, clientName, clientConfiguration, tokenFlow)); - - services.Register(() => new CtpClient(collection.BuildServiceProvider().GetService(), services.GetService(), services.GetService(), services.GetService()) { Name = clientName }, Lifestyle.Singleton); + + + services.Register(() => services.GetService().Create(clientName), Lifestyle.Singleton); collection.AddHttpClient(DefaultClientNames.Authorization); services.UseTokenProviders(collection.BuildServiceProvider().GetService()); @@ -208,8 +211,12 @@ private static IDictionary UseSingleClient(this Cont private static IHttpClientBuilder SetupClient(this Container services, IServiceCollection collection, string clientName, IClientConfiguration clientConfiguration, TokenFlow tokenFlow) { var httpClientBuilder = collection.AddHttpClient(clientName) - .ConfigureHttpClient(client => - client.BaseAddress = new Uri(clientConfiguration.ApiBaseAddress + clientConfiguration.ProjectKey + "/")) + .ConfigureHttpClient((c, client) => + { + client.BaseAddress = + new Uri(clientConfiguration.ApiBaseAddress + clientConfiguration.ProjectKey + "/"); + client.DefaultRequestHeaders.UserAgent.ParseAdd(c.GetService().UserAgent); + }) .AddHttpMessageHandler(c => { var providers = services.GetAllInstances(); From 202f9952df226a954a7796dc581e1ba6482ec60c Mon Sep 17 00:00:00 2001 From: Jens Schulze Date: Mon, 24 Feb 2020 14:59:24 +0100 Subject: [PATCH 2/2] add test for retrieving client by name --- .../ClientsTest.cs | 57 +++++++++++++++++++ .../DependencyInjectionSetup.cs | 4 +- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/commercetools.Sdk/IntegrationTests/commercetools.Sdk.IntegrationTests/ClientsTest.cs b/commercetools.Sdk/IntegrationTests/commercetools.Sdk.IntegrationTests/ClientsTest.cs index 07982f79..004df63f 100644 --- a/commercetools.Sdk/IntegrationTests/commercetools.Sdk.IntegrationTests/ClientsTest.cs +++ b/commercetools.Sdk/IntegrationTests/commercetools.Sdk.IntegrationTests/ClientsTest.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using commercetools.Sdk.Client; using commercetools.Sdk.Domain.Categories; +using commercetools.Sdk.HttpApi; using commercetools.Sdk.HttpApi.Domain.Exceptions; using commercetools.Sdk.HttpApi.Tokens; using Microsoft.Extensions.Configuration; @@ -51,6 +52,33 @@ public async Task MultipleClientsSimpleInjector() Assert.IsType(t2); } + [Fact] + public async Task MultipleClientsByNameSimpleInjector() + { + var services = new Container(); + var configuration = new ConfigurationBuilder(). + AddJsonFile("appsettings.test.json"). + AddJsonFile("appsettings.test.Development.json", true). + // https://www.jerriepelser.com/blog/aspnet-core-no-more-worries-about-checking-in-secrets/ + AddUserSecrets(). + AddEnvironmentVariables("CTP_"). + Build(); + + services.UseCommercetools(configuration, new Dictionary() + { + { "Client", TokenFlow.ClientCredentials }, + { "TokenClient", TokenFlow.ClientCredentials } + }); + var clientFactory = services.GetService(); + var client1 = clientFactory.Create("Client"); + var client2 = clientFactory.Create("TokenClient"); + + var t1 = await client1.ExecuteAsync(new GetProjectCommand()); + Assert.IsType(t1); + var t2 = await client2.ExecuteAsync(new GetProjectCommand()); + Assert.IsType(t2); + } + [Fact] public async Task MultipleClientsBuiltIn() { @@ -81,6 +109,35 @@ public async Task MultipleClientsBuiltIn() Assert.IsType(t2); } + [Fact] + public async Task MultipleClientsByNameBuiltIn() + { + var services = new ServiceCollection(); + var configuration = new ConfigurationBuilder(). + AddJsonFile("appsettings.test.json"). + AddJsonFile("appsettings.test.Development.json", true). + // https://www.jerriepelser.com/blog/aspnet-core-no-more-worries-about-checking-in-secrets/ + AddUserSecrets(). + AddEnvironmentVariables("CTP_"). + Build(); + + services.UseCommercetools(configuration, new Dictionary() + { + { "Client", TokenFlow.ClientCredentials }, + { "TokenClient", TokenFlow.ClientCredentials } + }); + var serviceProvider = services.BuildServiceProvider(); + + var clientFactory = serviceProvider.GetService(); + var client1 = clientFactory.Create("Client"); + var client2 = clientFactory.Create("TokenClient"); + + var t1 = await client1.ExecuteAsync(new GetProjectCommand()); + Assert.IsType(t1); + var t2 = await client2.ExecuteAsync(new GetProjectCommand()); + Assert.IsType(t2); + } + [Fact] public async void TestConcurrentRequestsSimpleInject() { diff --git a/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs b/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs index fce0624a..d3acf26f 100644 --- a/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs +++ b/commercetools.Sdk/commercetools.Sdk.SimpleInjector/DependencyInjectionSetup.cs @@ -211,11 +211,11 @@ private static IDictionary UseSingleClient(this Cont private static IHttpClientBuilder SetupClient(this Container services, IServiceCollection collection, string clientName, IClientConfiguration clientConfiguration, TokenFlow tokenFlow) { var httpClientBuilder = collection.AddHttpClient(clientName) - .ConfigureHttpClient((c, client) => + .ConfigureHttpClient(client => { client.BaseAddress = new Uri(clientConfiguration.ApiBaseAddress + clientConfiguration.ProjectKey + "/"); - client.DefaultRequestHeaders.UserAgent.ParseAdd(c.GetService().UserAgent); + client.DefaultRequestHeaders.UserAgent.ParseAdd(services.GetService().UserAgent); }) .AddHttpMessageHandler(c => {