Closed LadislavBohm closed 3 years ago
I'm not sure I fully understand the underlying problem. Can you help me with this by answering my following questions?
I am trying to register an implementation based on the fact that another specific implementation already exists in a container.
What prevents you from making all registrations, even if they aren't used? For instance:
var awsSection = Configuration.GetSection("AwsS3");
var blobSection = Configuration.GetSection("AzureBlobStorage");
container.RegisterInstance(new AwsS3Options(...));
container.RegisterInstance(new AzureBlobStorageOptions(...));
Type storageImplementation = awsSection != null
? typeof(AwsS3FileStorage)
: (blobSection != null ? typeof(AzureBlobStorage) : throw new Exception( "No storage config"));
container.Register(typeof(IFileStorage), storageImplementation, Lifestyle.Scoped);
Would a construct such as follows work for you? And if not, can you explain why it wouldn't work?
var awsSection = Configuration.GetSection("AwsS3");
var blobSection = Configuration.GetSection("AzureBlobStorage");
if (awsSection != null)
{
container.RegisterInstance(new AwsS3Options(...));
container.Register<IFileStorage, AwsS3FileStorage>(Lifestyle.Scoped);
}
else if (blobSection != null)
{
container.RegisterInstance(new AzureBlobStorageOptions(...));
container.Register<IFileStorage, AzureBlobStorage>(Lifestyle.Scoped);
}
else
{
throw new ConfigurationErrorsException(
"Could not find any file storage configuration");
}
By answering these questions you'll give me a better understanding of your problem, which hopefully allows me to give you the answer that best suits your needs.
Thank you for a great answer.
After looking at your code the only reason why I am not able to use it as you suggest is that services (AwsS3FileStorage, AzureBlobStorage) get registered in a different assembly (specifically in SI Package). While options (AwsS3Options, AzureBlobStorageOptions) get registered in a client type of project/assembly (like an API).
Although after reading what I just wrote above I think that what I am doing is probably not correct. The assembly that contains configurations (appsettings) should decide what gets registered and thus I should probably move the service registration there.
The assembly that contains configurations (appsettings) should decide what gets registered and thus I should probably move the service registration there.
That certainly sounds like a good idea. You typically want to keep all registrations inside the Composition Root.
If, however, you need to probe the container for existing registrations, you can do so by calling Container.GetRegistration(Type, false)
.
Thank you again, I modified my code and used Container.GetRegistration. I am now able to get exactly what I initially wanted and with a bit cleaner approach.
I am trying to register an implementation based on the fact that another specific implementation already exists in a container. If not I want to register another implementation.
So basically the question is how to register ServiceA only if ServiceAOptions is registered within the container and register ServiceB only if ServiceBOptions are registered.
Real-life use case is that I have a code that conditionally registers IOptions<OptionsA/B> based on their existence in appsettings.json. With a few helpers that I wrote I can have a code like this:
My registration using AutoFac would look like this:
As you can see I can just change appsettings and my app works with either of the two services. I don't seem to be able to achieve the same result with RegisterConditional or any of the overloads.