diff --git a/extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptions.cs b/extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptions.cs
index e137c66fd175..21e9e2611f75 100644
--- a/extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptions.cs
+++ b/extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptions.cs
@@ -13,7 +13,7 @@
* permissions and limitations under the License.
*/
using Amazon.Runtime;
-
+using AWSSDK.Extensions.NETCore.Setup;
using Microsoft.Extensions.Logging;
namespace Amazon.Extensions.NETCore.Setup
@@ -92,18 +92,6 @@ internal set
///
public LoggingSetting Logging { get; set; }
- ///
- /// Create a service client for the specified service interface using the options set in this instance.
- /// For example if T is set to IAmazonS3 then the AmazonS3ServiceClient which implements IAmazonS3 is created
- /// and returned.
- ///
- /// The service interface that a service client will be created for.
- /// The service client that implements the service interface.
- public T CreateServiceClient() where T : class, IAmazonService
- {
- return new ClientFactory(this).CreateServiceClient((ILogger)null, this) as T;
- }
-
///
/// Container for logging settings of the SDK
///
diff --git a/extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptionsExtensions.cs b/extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptionsExtensions.cs
new file mode 100644
index 000000000000..d7f4341f61f0
--- /dev/null
+++ b/extensions/src/AWSSDK.Extensions.NETCore.Setup/AWSOptionsExtensions.cs
@@ -0,0 +1,27 @@
+using Amazon.Extensions.NETCore.Setup;
+using Amazon.Runtime;
+
+namespace AWSSDK.Extensions.NETCore.Setup
+{
+ ///
+ ///
+ ///
+ public static class AWSOptionsExtensions
+ {
+ ///
+ /// Create a service client for the specified service interface using the options set in this instance.
+ /// For example if T is set to IAmazonS3 then the AmazonS3ServiceClient which implements IAmazonS3 is created
+ /// and returned.
+ ///
+ /// The service interface that a service client will be created for.
+ /// The service client that implements the service interface.
+ public static T CreateServiceClient(this AWSOptions options)
+ where T : class, IAmazonService
+ {
+ var credentials = new DefaultAWSCredentials(options, null);
+ var clientFactory = new ClientFactory(options, credentials, null);
+
+ return clientFactory.CreateServiceClient() as T;
+ }
+ }
+}
\ No newline at end of file
diff --git a/extensions/src/AWSSDK.Extensions.NETCore.Setup/ClientFactory.cs b/extensions/src/AWSSDK.Extensions.NETCore.Setup/ClientFactory.cs
index 26c402eada88..503fbee761c5 100644
--- a/extensions/src/AWSSDK.Extensions.NETCore.Setup/ClientFactory.cs
+++ b/extensions/src/AWSSDK.Extensions.NETCore.Setup/ClientFactory.cs
@@ -21,6 +21,7 @@
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;
using Amazon.Runtime.Credentials.Internal;
+using AWSSDK.Extensions.NETCore.Setup;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -36,68 +37,45 @@ internal class ClientFactory
private static readonly Type[] EMPTY_TYPES = Array.Empty();
private static readonly object[] EMPTY_PARAMETERS = Array.Empty();
- private AWSOptions _awsOptions;
+ private readonly AWSOptions _options;
+ private readonly AWSCredentials _credentials;
+ private readonly ILogger _logger;
///
/// Constructs an instance of the ClientFactory
///
/// The AWS options used for creating service clients.
- internal ClientFactory(AWSOptions awsOptions)
- {
- _awsOptions = awsOptions;
- }
-
- ///
- /// Creates the AWS service client that implements the service client interface. The AWSOptions object
- /// will be searched for in the IServiceProvider.
- ///
- /// The dependency injection provider.
- /// The AWS service client
- internal object CreateServiceClient(IServiceProvider provider)
+ ///
+ ///
+ internal ClientFactory(AWSOptions awsOptions, AWSCredentials credentials, ILogger logger)
{
- var loggerFactory = provider.GetService();
- var logger = loggerFactory?.CreateLogger("AWSSDK");
-
- var options = _awsOptions ?? provider.GetService();
- if(options == null)
- {
- var configuration = provider.GetService();
- 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));
+ _credentials = credentials ?? throw new ArgumentNullException(nameof(credentials));
+ _logger = logger;
}
///
- /// 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.
///
- /// Logger instance for writing diagnostic logs.
- /// The AWS options used for creating the service client.
/// The AWS service client
- internal IAmazonService CreateServiceClient(ILogger logger, AWSOptions options)
+ internal IAmazonService CreateServiceClient()
{
- PerformGlobalConfig(logger, options);
- var credentials = CreateCredentials(logger, options);
+ PerformGlobalConfig(_logger, _options);
+ var credentials = _credentials;
- 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;
}
@@ -165,52 +143,6 @@ private static AmazonServiceClient CreateClient(AWSCredentials credentials, Clie
#endif
}
- ///
- /// Creates the AWSCredentials using either the profile indicated from the AWSOptions object
- /// of the SDK fallback credentials search.
- ///
- ///
- ///
- ///
- private static AWSCredentials CreateCredentials(ILogger logger, AWSOptions options)
- {
- if (options != null)
- {
- if (options.Credentials != null)
- {
- logger?.LogInformation("Using AWS credentials specified with the AWSOptions.Credentials property");
- return options.Credentials;
- }
- if (!string.IsNullOrEmpty(options.Profile))
- {
- var chain = new CredentialProfileStoreChain(options.ProfilesLocation);
- AWSCredentials result;
- if (chain.TryGetAWSCredentials(options.Profile, out result))
- {
- logger?.LogInformation($"Found AWS credentials for the profile {options.Profile}");
- return result;
- }
- else
- {
- logger?.LogInformation($"Failed to find AWS credentials for the profile {options.Profile}");
- }
- }
- }
-
- var credentials = DefaultIdentityResolverConfiguration.ResolveDefaultIdentity();
- if (credentials == null)
- {
- logger?.LogError("Last effort to find AWS Credentials with AWS SDK's default credential search failed");
- throw new AmazonClientException("Failed to find AWS Credentials for constructing AWS service client");
- }
- else
- {
- logger?.LogInformation("Found credentials using the AWS SDK's default credential search");
- }
-
- return credentials;
- }
-
///
/// Creates the ClientConfig object for the service client.
///
diff --git a/extensions/src/AWSSDK.Extensions.NETCore.Setup/DefaultAWSCredentials.cs b/extensions/src/AWSSDK.Extensions.NETCore.Setup/DefaultAWSCredentials.cs
new file mode 100644
index 000000000000..7f7439187535
--- /dev/null
+++ b/extensions/src/AWSSDK.Extensions.NETCore.Setup/DefaultAWSCredentials.cs
@@ -0,0 +1,71 @@
+using Amazon.Extensions.NETCore.Setup;
+using Amazon.Runtime;
+using Amazon.Runtime.CredentialManagement;
+using Amazon.Runtime.Credentials.Internal;
+using Microsoft.Extensions.Logging;
+
+namespace AWSSDK.Extensions.NETCore.Setup
+{
+ ///
+ ///
+ ///
+ public class DefaultAWSCredentials : AWSCredentials
+ {
+ private readonly AWSOptions _options;
+ private readonly ILogger _logger;
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public DefaultAWSCredentials(AWSOptions awsOptions, ILogger logger)
+ {
+ _options = awsOptions;
+ _logger = logger;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public override ImmutableCredentials GetCredentials()
+ {
+ if (_options != null)
+ {
+ if (_options.Credentials != null)
+ {
+ _logger?.LogInformation("Using AWS credentials specified with the AWSOptions.Credentials property");
+ return _options.Credentials.GetCredentials();
+ }
+ if (!string.IsNullOrEmpty(_options.Profile))
+ {
+ var chain = new CredentialProfileStoreChain(_options.ProfilesLocation);
+ AWSCredentials result;
+ if (chain.TryGetAWSCredentials(_options.Profile, out result))
+ {
+ _logger?.LogInformation($"Found AWS credentials for the profile {_options.Profile}");
+ return result.GetCredentials();
+ }
+ else
+ {
+ _logger?.LogInformation($"Failed to find AWS credentials for the profile {_options.Profile}");
+ }
+ }
+ }
+
+ var credentials = DefaultIdentityResolverConfiguration.ResolveDefaultIdentity();
+ if (credentials == null)
+ {
+ _logger?.LogError("Last effort to find AWS Credentials with AWS SDK's default credential search failed");
+ throw new AmazonClientException("Failed to find AWS Credentials for constructing AWS service client");
+ }
+ else
+ {
+ _logger?.LogInformation("Found credentials using the AWS SDK's default credential search");
+ }
+
+ return credentials.GetCredentials();
+ }
+ }
+}
\ No newline at end of file
diff --git a/extensions/src/AWSSDK.Extensions.NETCore.Setup/ServiceCollectionExtensions.cs b/extensions/src/AWSSDK.Extensions.NETCore.Setup/ServiceCollectionExtensions.cs
index c0cf329b5104..35658fcc78ed 100644
--- a/extensions/src/AWSSDK.Extensions.NETCore.Setup/ServiceCollectionExtensions.cs
+++ b/extensions/src/AWSSDK.Extensions.NETCore.Setup/ServiceCollectionExtensions.cs
@@ -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
{
@@ -63,6 +65,94 @@ public static IServiceCollection AddDefaultAWSOptions(
return collection;
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddAWSCredentials(
+ this IServiceCollection collection,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton)
+ {
+ collection.Add(new ServiceDescriptor(typeof(AWSCredentials), sp => sp.CreateDefaultAWSCredentials(), lifetime));
+ return collection;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddAWSCredentials(
+ this IServiceCollection collection,
+ AWSCredentials credentials)
+ {
+ collection.Add(new ServiceDescriptor(typeof(AWSCredentials), credentials));
+ return collection;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddAWSCredentials(
+ this IServiceCollection collection,
+ Func credentialsFunc,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton)
+ {
+ collection.Add(new ServiceDescriptor(typeof(AWSCredentials), credentialsFunc, lifetime));
+ return collection;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection TryAddAWSCredentials(
+ this IServiceCollection collection,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton)
+ {
+ collection.TryAdd(new ServiceDescriptor(typeof(AWSCredentials), sp => sp.CreateDefaultAWSCredentials(), lifetime));
+ return collection;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection TryAddAWSCredentials(
+ this IServiceCollection collection,
+ AWSCredentials credentials)
+ {
+ collection.TryAdd(new ServiceDescriptor(typeof(AWSCredentials), credentials));
+ return collection;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection TryAddAWSCredentials(
+ this IServiceCollection collection,
+ Func credentialsFunc,
+ ServiceLifetime lifetime = ServiceLifetime.Singleton)
+ {
+ collection.TryAdd(new ServiceDescriptor(typeof(AWSCredentials), credentialsFunc, lifetime));
+ return collection;
+ }
+
///
/// 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.
@@ -106,7 +196,7 @@ public static IServiceCollection TryAddDefaultAWSOptions(
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection AddAWSService(this IServiceCollection collection, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- return AddAWSService(collection, null, lifetime);
+ return AddAWSService(collection, options: null, lifetime);
}
///
@@ -121,10 +211,24 @@ public static IServiceCollection AddAWSService(this IServiceCollection collec
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection AddAWSService(this IServiceCollection collection, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- Func factory =
- new ClientFactory(options).CreateServiceClient;
+ var descriptor = new ServiceDescriptor(typeof(T), sp => CreateServiceClient(options, sp), lifetime);
+ collection.Add(descriptor);
+ return collection;
+ }
- var descriptor = new ServiceDescriptor(typeof(T), factory, lifetime);
+ ///
+ /// Adds the Amazon service client to the dependency injection framework. The Amazon service client is not
+ /// created until it is requested. If the ServiceLifetime property is set to Singleton, the default, then the same
+ /// instance will be reused for the lifetime of the process and the object should not be disposed.
+ ///
+ /// The AWS service interface, like IAmazonS3.
+ ///
+ /// A func that resolves the AWS options used to create the service client overriding the default AWS options added using AddDefaultAWSOptions.
+ /// The lifetime of the service client created. The default is Singleton.
+ /// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
+ public static IServiceCollection AddAWSService(this IServiceCollection collection, Func optionsFunc, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
+ {
+ var descriptor = new ServiceDescriptor(typeof(T), sp => CreateServiceClient(optionsFunc(sp), sp), lifetime);
collection.Add(descriptor);
return collection;
}
@@ -140,7 +244,7 @@ public static IServiceCollection AddAWSService(this IServiceCollection collec
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection TryAddAWSService(this IServiceCollection collection, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- return TryAddAWSService(collection, null, lifetime);
+ return TryAddAWSService(collection, options: null, lifetime);
}
///
@@ -155,14 +259,28 @@ public static IServiceCollection TryAddAWSService(this IServiceCollection col
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection TryAddAWSService(this IServiceCollection collection, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- Func factory =
- new ClientFactory(options).CreateServiceClient;
+ var descriptor = new ServiceDescriptor(typeof(T), sp => CreateServiceClient(options, sp), lifetime);
+ collection.TryAdd(descriptor);
+ return collection;
+ }
- var descriptor = new ServiceDescriptor(typeof(T), factory, lifetime);
+ ///
+ /// Adds the Amazon service client to the dependency injection framework if the service type hasn't already been registered.
+ /// The Amazon service client is not created until it is requested. If the ServiceLifetime property is set to Singleton,
+ /// the default, then the same instance will be reused for the lifetime of the process and the object should not be disposed.
+ ///
+ /// The AWS service interface, like IAmazonS3.
+ ///
+ /// A func that resolves the AWS options used to create the service client overriding the default AWS options added using AddDefaultAWSOptions.
+ /// The lifetime of the service client created. The default is Singleton.
+ /// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
+ public static IServiceCollection TryAddAWSService(this IServiceCollection collection, Func optionsFunc, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
+ {
+ var descriptor = new ServiceDescriptor(typeof(T), sp => CreateServiceClient(optionsFunc(sp), sp), lifetime);
collection.TryAdd(descriptor);
return collection;
}
-
+
#if NET8_0_OR_GREATER
///
@@ -177,7 +295,7 @@ public static IServiceCollection TryAddAWSService(this IServiceCollection col
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection AddKeyedAWSService(this IServiceCollection collection, object serviceKey, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- return AddKeyedAWSService(collection, serviceKey, null, lifetime);
+ return AddKeyedAWSService(collection, serviceKey, options: null, lifetime);
}
///
@@ -193,9 +311,25 @@ public static IServiceCollection AddKeyedAWSService(this IServiceCollection c
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection AddKeyedAWSService(this IServiceCollection collection, object serviceKey, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- object Factory(IServiceProvider sp, object key) => new ClientFactory(options).CreateServiceClient(sp);
+ var descriptor = new ServiceDescriptor(typeof(T), serviceKey, (sp, _) => CreateServiceClient(options, sp), lifetime);
+ collection.Add(descriptor);
+ return collection;
+ }
- var descriptor = new ServiceDescriptor(typeof(T), serviceKey, Factory, lifetime);
+ ///
+ /// Adds the Amazon service client to the dependency injection framework with a key. The Amazon service client is not
+ /// created until it is requested. If the ServiceLifetime property is set to Singleton, the default, then the same
+ /// instance will be reused for the lifetime of the process and the object should not be disposed.
+ ///
+ /// The AWS service interface, like IAmazonS3
+ ///
+ /// The key with which the service will be added in the dependency injection framework.
+ /// A func that resolves the AWS options used to create the service client overriding the default AWS options added using AddDefaultAWSOptions.
+ /// The lifetime of the service client created. The default is Singleton.
+ /// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
+ public static IServiceCollection AddKeyedAWSService(this IServiceCollection collection, object serviceKey, Func optionsFunc, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
+ {
+ var descriptor = new ServiceDescriptor(typeof(T), serviceKey, (sp, _) => CreateServiceClient(optionsFunc(sp), sp), lifetime);
collection.Add(descriptor);
return collection;
}
@@ -212,7 +346,7 @@ public static IServiceCollection AddKeyedAWSService(this IServiceCollection c
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection TryAddKeyedAWSService(this IServiceCollection collection, object serviceKey, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- return TryAddKeyedAWSService(collection, serviceKey, null, lifetime);
+ return TryAddKeyedAWSService(collection, serviceKey, options: null, lifetime);
}
///
@@ -228,12 +362,45 @@ public static IServiceCollection TryAddKeyedAWSService(this IServiceCollectio
/// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
public static IServiceCollection TryAddKeyedAWSService(this IServiceCollection collection, object serviceKey, AWSOptions options, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
{
- object Factory(IServiceProvider sp, object key) => new ClientFactory(options).CreateServiceClient(sp);
+ var descriptor = new ServiceDescriptor(typeof(T), serviceKey, (sp, _) => CreateServiceClient(options, sp), lifetime);
+ collection.TryAdd(descriptor);
+ return collection;
+ }
- var descriptor = new ServiceDescriptor(typeof(T), serviceKey, Factory, lifetime);
+ ///
+ /// Adds the Amazon service client to the dependency injection framework with a key if the service type hasn't already been registered with the same key.
+ /// The Amazon service client is not created until it is requested. If the ServiceLifetime property is set to Singleton, the default, then the same
+ /// instance will be reused for the lifetime of the process and the object should not be disposed.
+ ///
+ /// The AWS service interface, like IAmazonS3
+ ///
+ /// The key with which the service will be added in the dependency injection framework.
+ /// A func that resolves the AWS options used to create the service client overriding the default AWS options added using AddDefaultAWSOptions.
+ /// The lifetime of the service client created. The default is Singleton.
+ /// Returns back the IServiceCollection to continue the fluent system of IServiceCollection.
+ public static IServiceCollection TryAddKeyedAWSService(this IServiceCollection collection, object serviceKey, Func optionsFunc, ServiceLifetime lifetime = ServiceLifetime.Singleton) where T : IAmazonService
+ {
+ var descriptor = new ServiceDescriptor(typeof(T), serviceKey, (sp, _) => CreateServiceClient(optionsFunc(sp), sp), lifetime);
collection.TryAdd(descriptor);
return collection;
}
#endif
+
+ private static object CreateServiceClient(AWSOptions options, IServiceProvider sp) where T : IAmazonService
+ {
+ var logger = sp.GetService();
+ var awsOptions = options ?? sp.GetService() ?? new AWSOptions();
+ var credentialsFactory = sp.GetService() ?? sp.CreateDefaultAWSCredentials(awsOptions);
+
+ var factory = new ClientFactory(awsOptions, credentialsFactory, logger);
+
+ return factory.CreateServiceClient();
+ }
+
+ private static AWSCredentials CreateDefaultAWSCredentials(this IServiceProvider sp, AWSOptions options = null)
+ {
+ options = options ?? sp.GetService() ?? new AWSOptions();
+ return new DefaultAWSCredentials(options, sp.GetService());
+ }
}
}
diff --git a/extensions/test/NETCore.SetupTests/ConfigurationTests.cs b/extensions/test/NETCore.SetupTests/ConfigurationTests.cs
index 731e5f2edefb..cf7aeaa97d25 100644
--- a/extensions/test/NETCore.SetupTests/ConfigurationTests.cs
+++ b/extensions/test/NETCore.SetupTests/ConfigurationTests.cs
@@ -10,6 +10,7 @@
using Amazon;
using Amazon.S3;
using Amazon.Runtime;
+using AWSSDK.Extensions.NETCore.Setup;
namespace NETCore.SetupTests
{