I am creating an Azure Function App in Visual Studio with c# and .NET 6.
I have a service I created (CosmosDBService) that implements the interface ICosmosDBService:
public class CosmosDbService : ICosmosDbService
{
private Container? _container = null;
public CosmosDbService(
CosmosClient cosmosDbClient,
string databaseName,
string containerName)
{
_container = cosmosDbClient.GetContainer(databaseName, containerName);
}
I want to pass two different instances of this service into the Function App. Each service instance would represent a different container.
How would I set this up in Startup:FunctionsApp class using the FunctionsHostBuilder?
CodePudding user response:
Default DI container does not support named such scenarios so you have next options - either create separate interfaces and implementations (and register/resolve them) for each databaseName-containerName pair or create a factory and use it to generate desired CosmosDbService
instance:
public interface ICosmosDbServiceFactory
{
ICosmosDbService Create(string databaseName, string containerName);
}
class CosmosDbServiceFactory : ICosmosDbServiceFactory
{
private readonly IServiceProvider _serviceProvider;
public CosmosDbServiceFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public ICosmosDbService Create(string databaseName, string containerName) => new CosmosDbService(
_serviceProvider.GetRequiredService<CosmosClient>(),
databaseName,
containerName
);
}
Register it with appropriate lifetime and inject it into corresponding class and use it in the constructor to resolve required ICosmosDbService
instances.
CodePudding user response:
You can do this, but I wouldn't recommend it. For instance in your start up if you had the following code:
services.AddSingleton<ICosmosDbService, CosmosDbService>();
services.AddSingleton<ICosmosDbService, OtherCosmosDbService>();
both instances would be registered in the Di container. If you had a class that depends on this interface, the following constructor would result in OtherCosmosDbService being injected:
public class SomeClass {
private readonly ICosmosDbService _service;
public SomeClass(ICosmosDbService service){
_service = service; // This would be OtherCosmosDbService
}
}
Both would be registered and in this instance, the last one registered "wins". If you wanted to get both then you could change the constructor to this:
public SomeClass(IEnumerable<ICosmosDbService> services){
// Write logic to handle finding which one you want
}
Honestly, I would go with Guru Stron's suggestion of creating separate interfaces for each container and registering them separately.