Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor http client di #104

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -51,6 +52,33 @@ public async Task MultipleClientsSimpleInjector()
Assert.IsType<Domain.Projects.Project>(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<ServiceProviderFixture>().
AddEnvironmentVariables("CTP_").
Build();

services.UseCommercetools(configuration, new Dictionary<string, TokenFlow>()
{
{ "Client", TokenFlow.ClientCredentials },
{ "TokenClient", TokenFlow.ClientCredentials }
});
var clientFactory = services.GetService<ICtpClientFactory>();
var client1 = clientFactory.Create("Client");
var client2 = clientFactory.Create("TokenClient");

var t1 = await client1.ExecuteAsync(new GetProjectCommand());
Assert.IsType<Domain.Projects.Project>(t1);
var t2 = await client2.ExecuteAsync(new GetProjectCommand());
Assert.IsType<Domain.Projects.Project>(t2);
}

[Fact]
public async Task MultipleClientsBuiltIn()
{
Expand Down Expand Up @@ -81,6 +109,35 @@ public async Task MultipleClientsBuiltIn()
Assert.IsType<Domain.Projects.Project>(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<ServiceProviderFixture>().
AddEnvironmentVariables("CTP_").
Build();

services.UseCommercetools(configuration, new Dictionary<string, TokenFlow>()
{
{ "Client", TokenFlow.ClientCredentials },
{ "TokenClient", TokenFlow.ClientCredentials }
});
var serviceProvider = services.BuildServiceProvider();

var clientFactory = serviceProvider.GetService<ICtpClientFactory>();
var client1 = clientFactory.Create("Client");
var client2 = clientFactory.Create("TokenClient");

var t1 = await client1.ExecuteAsync(new GetProjectCommand());
Assert.IsType<Domain.Projects.Project>(t1);
var t2 = await client2.ExecuteAsync(new GetProjectCommand());
Assert.IsType<Domain.Projects.Project>(t2);
}

[Fact]
public async void TestConcurrentRequestsSimpleInject()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ public void GetCategoryById()
IClient commerceToolsClient = new CtpClient(
mockHttpClientFactory.Object,
this.clientFixture.GetService<IHttpApiCommandFactory>(),
this.clientFixture.GetService<ISerializerService>(),
this.clientFixture.GetService<IUserAgentProvider>()
this.clientFixture.GetService<ISerializerService>()
);
string categoryId = "2bafc816-4223-4ff0-ac8a-0f08a8f29fd6";
Category category = commerceToolsClient.ExecuteAsync(new GetByIdCommand<Category>(new Guid(categoryId))).Result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ public void GetMessageByIdForCategoryCreatedAction()
IClient commerceToolsClient = new CtpClient(
mockHttpClientFactory.Object,
this.clientFixture.GetService<IHttpApiCommandFactory>(),
this.clientFixture.GetService<ISerializerService>(),
this.clientFixture.GetService<IUserAgentProvider>()
this.clientFixture.GetService<ISerializerService>()
);
string messageId = "174adf2f-783f-4ce5-a2d5-ee7d3ee7caf4";
CategoryCreatedMessage categoryCreatedMessage = commerceToolsClient.ExecuteAsync(new GetByIdCommand<Message>(new Guid(messageId))).Result as CategoryCreatedMessage;
Expand Down
20 changes: 2 additions & 18 deletions commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Net.Http;
using System.Threading.Tasks;
using Client;
using DelegatingHandlers;
using Domain.Exceptions;
using Serialization;

Expand All @@ -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<T> ExecuteAsync<T>(Command<T> command)
{
Expand Down
25 changes: 25 additions & 0 deletions commercetools.Sdk/commercetools.Sdk.HttpApi/CtpClientFactory.cs
Original file line number Diff line number Diff line change
@@ -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 };
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public static class DependencyInjectionSetup
{
public static IDictionary<string, IHttpClientBuilder> UseHttpApi(this IServiceCollection services, IConfiguration configuration, IDictionary<string, TokenFlow> clients)
{
services.UseHttpApiDefaults();

if (clients.Count() == 1)
{
return services.UseSingleClient(configuration, clients.First().Key, clients.First().Value);
Expand All @@ -34,7 +36,7 @@ public static IDictionary<string, IHttpClientBuilder> UseHttpApi(this IServiceCo

private static IDictionary<string, IHttpClientBuilder> UseMultipleClients(this IServiceCollection services, IConfiguration configuration, IDictionary<string, TokenFlow> clients)
{
services.UseHttpApiDefaults();
services.AddSingleton<ICtpClientFactory, CtpClientFactory>();
var builders = new ConcurrentDictionary<string, IHttpClientBuilder>();
foreach (KeyValuePair<string, TokenFlow> client in clients)
{
Expand All @@ -45,19 +47,19 @@ private static IDictionary<string, IHttpClientBuilder> UseMultipleClients(this I
Validator.ValidateObject(clientConfiguration, new ValidationContext(clientConfiguration), true);

builders.TryAdd(clientName, services.SetupClient(clientName, clientConfiguration, tokenFlow));
services.AddSingleton<IClient>(c => new CtpClient(c.GetService<IHttpClientFactory>(), c.GetService<IHttpApiCommandFactory>(), c.GetService<ISerializerService>(), c.GetService<IUserAgentProvider>()) { Name = clientName });
services.AddSingleton(c => c.GetService<ICtpClientFactory>().Create(clientName));
}

return builders;
}

private static IDictionary<string, IHttpClientBuilder> UseSingleClient(this IServiceCollection services, IConfiguration configuration, string clientName, TokenFlow tokenFlow)
{
services.AddSingleton<ICtpClientFactory, CtpClientFactory>();
IClientConfiguration clientConfiguration = configuration.GetSection(clientName).Get<ClientConfiguration>();
Validator.ValidateObject(clientConfiguration, new ValidationContext(clientConfiguration), true);

services.UseHttpApiDefaults();
services.AddSingleton<IClient>(c => new CtpClient(c.GetService<IHttpClientFactory>(), c.GetService<IHttpApiCommandFactory>(), c.GetService<ISerializerService>(), c.GetService<IUserAgentProvider>()) { Name = clientName });
services.AddSingleton(c => c.GetService<ICtpClientFactory>().Create(clientName));

var builders = new ConcurrentDictionary<string, IHttpClientBuilder>();
builders.TryAdd(clientName, services.SetupClient(clientName, clientConfiguration, tokenFlow));
Expand All @@ -68,8 +70,12 @@ private static IDictionary<string, IHttpClientBuilder> 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<IUserAgentProvider>().UserAgent);
})
.AddHttpMessageHandler(c =>
{
var providers = c.GetServices<ITokenProvider>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using commercetools.Sdk.Client;

namespace commercetools.Sdk.HttpApi
{
public interface ICtpClientFactory
{
IClient Create(string name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ private static IDictionary<string, IHttpClientBuilder> UseMultipleClients(this C
{
var collection = new ServiceCollection();
services.UseHttpApiDefaults();
services.Register<ICtpClientFactory>(() => new CtpClientFactory(collection.BuildServiceProvider().GetService<IHttpClientFactory>(), services.GetService<IHttpApiCommandFactory>(), services.GetService<ISerializerService>()), Lifestyle.Singleton);

var builders = new ConcurrentDictionary<string, IHttpClientBuilder>();
var clientBuilders = new List<Registration>();
Expand All @@ -156,7 +157,7 @@ private static IDictionary<string, IHttpClientBuilder> UseMultipleClients(this C

builders.TryAdd(clientName, services.SetupClient(collection, clientName, clientConfiguration, tokenFlow));

clientBuilders.Add(Lifestyle.Singleton.CreateRegistration(() => new CtpClient(collection.BuildServiceProvider().GetService<IHttpClientFactory>(), services.GetService<IHttpApiCommandFactory>(), services.GetService<ISerializerService>(), services.GetService<IUserAgentProvider>()) { Name = clientName }, services));
clientBuilders.Add(Lifestyle.Singleton.CreateRegistration(() => services.GetService<ICtpClientFactory>().Create(clientName), services));
}
services.RegisterCollection<IClient>(clientBuilders);

Expand Down Expand Up @@ -189,15 +190,17 @@ private static IDictionary<string, IHttpClientBuilder> UseSingleClient(this Cont
{
var collection = new ServiceCollection();
services.UseHttpApiDefaults();
services.Register<ICtpClientFactory>(() => new CtpClientFactory(collection.BuildServiceProvider().GetService<IHttpClientFactory>(), services.GetService<IHttpApiCommandFactory>(), services.GetService<ISerializerService>()), Lifestyle.Singleton);

var configurationSection = configuration.GetSection(clientName);
IClientConfiguration clientConfiguration = configurationSection.Get<ClientConfiguration>();
Validator.ValidateObject(clientConfiguration, new ValidationContext(clientConfiguration), true);

var builders = new ConcurrentDictionary<string, IHttpClientBuilder>();
builders.TryAdd(clientName, services.SetupClient(collection, clientName, clientConfiguration, tokenFlow));

services.Register<IClient>(() => new CtpClient(collection.BuildServiceProvider().GetService<IHttpClientFactory>(), services.GetService<IHttpApiCommandFactory>(), services.GetService<ISerializerService>(), services.GetService<IUserAgentProvider>()) { Name = clientName }, Lifestyle.Singleton);


services.Register(() => services.GetService<ICtpClientFactory>().Create(clientName), Lifestyle.Singleton);

collection.AddHttpClient(DefaultClientNames.Authorization);
services.UseTokenProviders(collection.BuildServiceProvider().GetService<IHttpClientFactory>());
Expand All @@ -209,7 +212,11 @@ private static IHttpClientBuilder SetupClient(this Container services, IServiceC
{
var httpClientBuilder = collection.AddHttpClient(clientName)
.ConfigureHttpClient(client =>
client.BaseAddress = new Uri(clientConfiguration.ApiBaseAddress + clientConfiguration.ProjectKey + "/"))
{
client.BaseAddress =
new Uri(clientConfiguration.ApiBaseAddress + clientConfiguration.ProjectKey + "/");
client.DefaultRequestHeaders.UserAgent.ParseAdd(services.GetService<IUserAgentProvider>().UserAgent);
})
.AddHttpMessageHandler(c =>
{
var providers = services.GetAllInstances<ITokenProvider>();
Expand Down