Skip to content
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 @@ -106,7 +106,7 @@ internal set
/// <returns>The service client that implements the service interface.</returns>
public T CreateServiceClient<T>() where T : class, IAmazonService
{
return new ClientFactory<T>(this).CreateServiceClient((ILogger)null, this) as T;
return new ClientFactory<T>(this, CredentialsFactory, (ILogger)null).CreateServiceClient() as T;
}

/// <summary>
Expand Down
60 changes: 18 additions & 42 deletions extensions/src/AWSSDK.Extensions.NETCore.Setup/ClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,69 +37,45 @@ internal class ClientFactory<T>
private static readonly Type[] EMPTY_TYPES = Array.Empty<Type>();
private static readonly object[] EMPTY_PARAMETERS = Array.Empty<object>();

private AWSOptions _awsOptions;
private readonly AWSOptions _options;
private readonly IAWSCredentialsFactory _credentialsFactory;
private readonly ILogger _logger;

/// <summary>
/// Constructs an instance of the ClientFactory
/// </summary>
/// <param name="awsOptions">The AWS options used for creating service clients.</param>
internal ClientFactory(AWSOptions awsOptions)
{
_awsOptions = awsOptions;
}

/// <summary>
/// Creates the AWS service client that implements the service client interface. The AWSOptions object
/// will be searched for in the IServiceProvider.
/// </summary>
/// <param name="provider">The dependency injection provider.</param>
/// <returns>The AWS service client</returns>
internal object CreateServiceClient(IServiceProvider provider)
/// <param name="credentialsFactory"></param>
/// <param name="logger"></param>
internal ClientFactory(AWSOptions awsOptions, IAWSCredentialsFactory credentialsFactory, ILogger logger)
{
var loggerFactory = provider.GetService<Microsoft.Extensions.Logging.ILoggerFactory>();
var logger = loggerFactory?.CreateLogger("AWSSDK");

var options = _awsOptions ?? provider.GetService<AWSOptions>();
if(options == null)
{
var configuration = provider.GetService<IConfiguration>();
if(configuration != null)
{
options = configuration.GetAWSOptions();
if (options != null)
logger?.LogInformation("Found AWS options in IConfiguration");
}
}

return CreateServiceClient(logger, options);
_options = awsOptions ?? throw new ArgumentNullException(nameof(awsOptions));
_credentialsFactory = credentialsFactory ?? throw new ArgumentNullException(nameof(credentialsFactory));
_logger = logger;
}

/// <summary>
/// Creates the AWS service client that implements the service client interface. The AWSOptions object
/// will be searched for in the IServiceProvider.
/// Creates the AWS service client that implements the service client interface.
/// </summary>
/// <param name="logger">Logger instance for writing diagnostic logs.</param>
/// <param name="options">The AWS options used for creating the service client.</param>
/// <returns>The AWS service client</returns>
internal IAmazonService CreateServiceClient(ILogger logger, AWSOptions options)
internal IAmazonService CreateServiceClient()
{
PerformGlobalConfig(logger, options);
var credentialsFactory = options.CredentialsFactory ?? new DefaultAWSCredentialsFactory(options, logger);
var credentials = credentialsFactory.Create();
PerformGlobalConfig(_logger, _options);
var credentials = _credentialsFactory.Create();

if (!string.IsNullOrEmpty(options?.SessionRoleArn))
if (!string.IsNullOrEmpty(_options?.SessionRoleArn))
{
if (string.IsNullOrEmpty(options?.ExternalId))
if (string.IsNullOrEmpty(_options?.ExternalId))
{
credentials = new AssumeRoleAWSCredentials(credentials, options.SessionRoleArn, options.SessionName);
credentials = new AssumeRoleAWSCredentials(credentials, _options.SessionRoleArn, _options.SessionName);
}
else
{
credentials = new AssumeRoleAWSCredentials(credentials, options.SessionRoleArn, options.SessionName, new AssumeRoleAWSCredentialsOptions() { ExternalId = options.ExternalId });
credentials = new AssumeRoleAWSCredentials(credentials, _options.SessionRoleArn, _options.SessionName, new AssumeRoleAWSCredentialsOptions() { ExternalId = _options.ExternalId });
}
}

var config = CreateConfig(options);
var config = CreateConfig(_options);
var client = CreateClient(credentials, config);
return client as IAmazonService;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@

using Amazon.Runtime;
using Amazon.Extensions.NETCore.Setup;
using AWSSDK.Extensions.NETCore.Setup;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;

namespace Microsoft.Extensions.DependencyInjection
{
Expand Down Expand Up @@ -63,6 +65,94 @@ public static IServiceCollection AddDefaultAWSOptions(
return collection;
}

/// <summary>
///
/// </summary>
/// <param name="collection"></param>
/// <param name="lifetime"></param>
/// <returns></returns>
public static IServiceCollection AddAWSCredentialsFactory(
this IServiceCollection collection,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
collection.Add(new ServiceDescriptor(typeof(IAWSCredentialsFactory), CreateDefaultCredentialsFactory, lifetime));
return collection;
}

/// <summary>
///
/// </summary>
/// <param name="collection"></param>
/// <param name="implementationFactory"></param>
/// <param name="lifetime"></param>
/// <returns></returns>
public static IServiceCollection AddAWSCredentialsFactory(
this IServiceCollection collection,
Func<IServiceProvider, IAWSCredentialsFactory> implementationFactory,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
collection.Add(new ServiceDescriptor(typeof(IAWSCredentialsFactory), implementationFactory, lifetime));
return collection;
}

/// <summary>
///
/// </summary>
/// <param name="collection"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public static IServiceCollection AddAWSCredentialsFactory(
this IServiceCollection collection,
IAWSCredentialsFactory credentials)
{
collection.Add(new ServiceDescriptor(typeof(IAWSCredentialsFactory), credentials));
return collection;
}

/// <summary>
///
/// </summary>
/// <param name="collection"></param>
/// <param name="lifetime"></param>
/// <returns></returns>
public static IServiceCollection TryAddAWSCredentialsFactory(
this IServiceCollection collection,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
collection.TryAdd(new ServiceDescriptor(typeof(IAWSCredentialsFactory), CreateDefaultCredentialsFactory, lifetime));
return collection;
}

/// <summary>
///
/// </summary>
/// <param name="collection"></param>
/// <param name="implementationFactory"></param>
/// <param name="lifetime"></param>
/// <returns></returns>
public static IServiceCollection TryAddAWSCredentialsFactory(
this IServiceCollection collection,
Func<IServiceProvider, IAWSCredentialsFactory> implementationFactory,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
collection.TryAdd(new ServiceDescriptor(typeof(IAWSCredentialsFactory), implementationFactory, lifetime));
return collection;
}

/// <summary>
///
/// </summary>
/// <param name="collection"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public static IServiceCollection TryAddAWSCredentialsFactory(
this IServiceCollection collection,
IAWSCredentialsFactory credentials)
{
collection.TryAdd(new ServiceDescriptor(typeof(IAWSCredentialsFactory), credentials));
return collection;
}

/// <summary>
/// Adds the AWSOptions object to the dependency injection framework providing information
/// that will be used to construct Amazon service clients if they haven't already been registered.
Expand Down Expand Up @@ -121,10 +211,7 @@ public static IServiceCollection AddAWSService<T>(this IServiceCollection collec
/// <returns>Returns back the IServiceCollection to continue the fluent system of IServiceCollection.</returns>
public static IServiceCollection AddAWSService<T>(this IServiceCollection collection, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
Func<IServiceProvider, object> factory =
new ClientFactory<T>(options).CreateServiceClient;

var descriptor = new ServiceDescriptor(typeof(T), factory, lifetime);
var descriptor = new ServiceDescriptor(typeof(T), sp => CreateServiceClient<T>(options, sp), lifetime);
collection.Add(descriptor);
return collection;
}
Expand Down Expand Up @@ -155,14 +242,11 @@ public static IServiceCollection TryAddAWSService<T>(this IServiceCollection col
/// <returns>Returns back the IServiceCollection to continue the fluent system of IServiceCollection.</returns>
public static IServiceCollection TryAddAWSService<T>(this IServiceCollection collection, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
Func<IServiceProvider, object> factory =
new ClientFactory<T>(options).CreateServiceClient;

var descriptor = new ServiceDescriptor(typeof(T), factory, lifetime);
var descriptor = new ServiceDescriptor(typeof(T), sp => CreateServiceClient<T>(options, sp), lifetime);
collection.TryAdd(descriptor);
return collection;
}

#if NET8_0_OR_GREATER

/// <summary>
Expand Down Expand Up @@ -193,9 +277,7 @@ public static IServiceCollection AddKeyedAWSService<T>(this IServiceCollection c
/// <returns>Returns back the IServiceCollection to continue the fluent system of IServiceCollection.</returns>
public static IServiceCollection AddKeyedAWSService<T>(this IServiceCollection collection, object serviceKey, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
object Factory(IServiceProvider sp, object key) => new ClientFactory<T>(options).CreateServiceClient(sp);

var descriptor = new ServiceDescriptor(typeof(T), serviceKey, Factory, lifetime);
var descriptor = new ServiceDescriptor(typeof(T), serviceKey, (sp, _) => CreateServiceClient<T>(options, sp), lifetime);
collection.Add(descriptor);
return collection;
}
Expand Down Expand Up @@ -228,12 +310,27 @@ public static IServiceCollection TryAddKeyedAWSService<T>(this IServiceCollectio
/// <returns>Returns back the IServiceCollection to continue the fluent system of IServiceCollection.</returns>
public static IServiceCollection TryAddKeyedAWSService<T>(this IServiceCollection collection, object serviceKey, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
object Factory(IServiceProvider sp, object key) => new ClientFactory<T>(options).CreateServiceClient(sp);

var descriptor = new ServiceDescriptor(typeof(T), serviceKey, Factory, lifetime);
var descriptor = new ServiceDescriptor(typeof(T), serviceKey, (sp, _) => CreateServiceClient<T>(options, sp), lifetime);
collection.TryAdd(descriptor);
return collection;
}
#endif

private static object CreateServiceClient<T>(AWSOptions options, IServiceProvider sp) where T : IAmazonService
{
var logger = sp.GetService<ILogger>();
var awsOptions = options ?? sp.GetService<AWSOptions>() ?? new AWSOptions();
var credentialsFactory = awsOptions.CredentialsFactory ?? sp.GetService<IAWSCredentialsFactory>() ?? new DefaultAWSCredentialsFactory(awsOptions, logger);

var factory = new ClientFactory<T>(awsOptions, credentialsFactory, logger);

return factory.CreateServiceClient();
}

private static IAWSCredentialsFactory CreateDefaultCredentialsFactory(IServiceProvider sp)
{
var options = sp.GetService<AWSOptions>() ?? new AWSOptions();
return new DefaultAWSCredentialsFactory(options, sp.GetService<ILogger>());
}
}
}