The issue is as follows:
I have to access 2 different S3 buckets and the way I have to create AmazonS3clients is as follows:
var client = new AmazonS3Client(accesKey,secretKey, bucketRegion);
Since I have 2 clients I ended up following the advice in the book "Dependency Injection Principles, Practices, and Patterns" and in particular the advice in Chapter 6 whereby instead of using an Abstract Factory, I end up using an Adapter.
Here is the code of interest:
static async Task Main(string[] args)
{
var s3Clients = new Dictionary<S3ClientType, IAmAnS3ClientQueryor>
{
{
S3ClientType.Discriminator1,
new S3Queryor(apiKey1, secretKey1, bucketRegion))
},
{
S3ClientType.Discriminator2,
new S3Queryor(new AmazonS3Client(apiKey2, secretKey2, bucketRegion))
},
};
IGetFileNames fileNamesGetter = new S3FileNamesGetter(s3Clients);
var uidMappingFileNames = fileNamesGetter.GetAsync(S3ClientType.Discriminator2, bucketName);
}
public interface IGetFileNames
{
IAsyncEnumerable<string> GetAsync(S3ClientType discriminator, string bucketName);
}
public class S3FileNamesGetter: IGetFileNames
{
private readonly IDictionary<S3ClientType, IAmAnS3ClientQueryor> s3Clients;
public S3FileNamesGetter(IDictionary<S3ClientType, IAmAnS3ClientQueryor> s3Clients)
{
this.s3Clients = s3Clients;
}
public IAsyncEnumerable<string> GetAsync(S3ClientType type, string bucketName)
{
return s3Clients[type].GetFileNames(bucketName, token);
}
}
public interface IAmAnS3ClientQueryor
{
IAsyncEnumerable<string> GetFileNames(string bucketName);
}
public class S3Queryor : IAmAnS3ClientQueryor
{
private readonly IAmazonS3 s3Client;
public S3Queryor(IAmazonS3 s3Client)
{
this.s3Client = s3Client;
}
public async IAsyncEnumerable<string> GetFileNames(string bucketName)
{
// Returns filenames from S3
}
}
In my attempt to use SimpleInjector, I have:
static async Task Main(string[] args)
{
var container = new Container();
Bootstrap.Start(container, bucketRegion);
var fileNamesGetter = container.GetInstance<IGetFileNames>();
var uidMappingFileNames =
fileNamesGetter.GetAsync(S3ClientType.Discriminator2, bucketName);
}
internal class Bootstrap
{
public static void Start(Container container, RegionEndpoint bucketRegion)
{
container.Register<S3FileNamesGetter>();
container.Options.EnableAutoVerification = false;
var client1 = new AmazonS3Client( apiKey1, secretKey1, bucketRegion);
var client2 = new AmazonS3Client( apiKey2, secretKey2, bucketRegion);
var s3ClientsQueryors = new Dictionary<S3ClientType, IAmAnS3ClientQueryor>
{
{
S3ClientType.Discriminator1, new S3Queryor(client1)
},
{
S3ClientType.Discriminator2, new S3Queryor(client2)
}
};
container.Collection.Register<IAmazonS3>(client1, client2);
container.RegisterInstance<IDictionary<S3ClientType, IAmAnS3ClientQueryor>>(s3ClientsQueryors);
container.RegisterInstance<IGetFileNames>(new S3FileNamesGetter(s3ClientsQueryors));
container.Register<IAmAnS3ClientQueryor, S3Queryor>();
container.Verify();
}
}
but when I run this code, I quite rightly get:
Unhandled exception. System.InvalidOperationException: The configuration is invalid. Creating the instance for type IAmAnS3ClientQueryor failed. The constructor of type S3Queryor contains the parameter with name 's3Client' and type IAmazonS3, bu t IAmazonS3 is not registered. For IAmazonS3 to be resolved, it must be registered in the container. There is, however, a registration for a collection of IAmazonS3 instances; Did you mean to depend on IEnumerable<IAmazonS3> instead? If you mean t to depend on IAmazonS3, you should use one of the Container.Register overloads instead of using Container.Collection.Register. Please see https://simpleinjector.org/collections for more information about registering and resolving collections. --->
The message is clear. However, the problem in the 1st instance is the fact that I have 2 S3 clients which I want to be eventually injected in S3Queryor
.
So the question is how to register my dependencies in Simple Injector to use the Adapter pattern.
=== EDIT after @Steven 1st comment.
I have created a repo of the code above here https://github.com/DavidSSL/SI-Trial
Here is the way to do it thanks to @Steven:
internal static class Bootstrap
{
public static void Start(Container container, RegionEndpoint bucketRegion)
{
container.RegisterInstance<IGetFileNames>(new S3FileNamesGetter(
new Dictionary<S3ClientType, IAmAnS3ClientQueryor>
{
{
S3ClientType.Discriminator1,
new S3Queryor(new AmazonS3Client("apiKey1", "secretKey1", bucketRegion))
},
{
S3ClientType.Discriminator2,
new S3Queryor(new AmazonS3Client("apiKey2", "secretKey2", bucketRegion))
},
}));
container.Options.EnableAutoVerification = false;
container.Verify();
}
}