1

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?

Guru Stron
  • 42,843
  • 5
  • 48
  • 70
Mike Lenart
  • 531
  • 3
  • 10
  • See [Dependency Injection Unity - Conditional Resolving](https://stackoverflow.com/a/32415954). Although that answer involves Unity, the design doesn't depend on any Unity-specific functionality to work. See Nick's answer for how to register multiple services with the same interface in .NET Core. – NightOwl888 May 24 '22 at 19:48

2 Answers2

1

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.

Guru Stron
  • 42,843
  • 5
  • 48
  • 70
0

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.

Nick Cipollina
  • 451
  • 3
  • 11