Pete Garafano
Pete Garafano

Reputation: 4923

Can't Get Concrete Type From Microsoft.Extensions.DependencyInjection.IServiceProvider

I am registering an interface (IFoo) with the Microsoft.Extensions.DependencyInjection service as follows:

servicesBuilder.AddSingleton<IFooRepository, FooInMemoryRepository>();

Almost exclusively I am agnostic on the concrete type when I resolve the dependency as such:

services.GetRequiredService<IFooRepository>()

In which case everything works fine. However in rare instances I need the concrete implementation (FooInMemoryRepository) so I want to resolve that directly. I tried calling that

services.GetRequiredService<FooInMemoryRepository>()

However this throws an exception:

System.InvalidOperationException: No service for type 'UserQuery+FooInMemoryRepository' has been registered.
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at UserQuery.Main() in C:\Users\User\AppData\Local\Temp\LINQPad5\_ntmafjyh\query_eecehy.cs:line 37

Sample code (LINQPad):

void Main()
{
    var servicesBuilder = new ServiceCollection();
    servicesBuilder.AddSingleton<IFooRepository, FooInMemoryRepository>();
    servicesBuilder.AddSingleton<IFooRepository, FooOtherRepository>();
    var services = servicesBuilder.BuildServiceProvider();
    try
    {
        var foos = services.GetServices<IFooRepository>();
        foreach(var foo in foos)
        {
            Console.WriteLine(foo.SomeMethod());
        }
        var ifoo = services.GetRequiredService<IFooRepository>();
        Console.WriteLine(ifoo.SomeMethod());
        var inMemoryRepo = services.GetRequiredService<FooInMemoryRepository>();
        Console.WriteLine(inMemoryRepo.SomeMethod());
    }
    catch(InvalidOperationException ioex)
    {
        Console.WriteLine(ioex.ToString());
    }
}

// Define other methods and classes here
public interface IFooRepository
{
    string SomeMethod();
}

public class FooInMemoryRepository : IFooRepository
{
    public string SomeMethod() => "InMemory Foo";
}

public class FooOtherRepository : IFooRepository
{
    public string SomeMethod() => "Other Foo";
}

Output:

InMemory Foo
Other Foo
Other Foo
System.InvalidOperationException: No service for type 'UserQuery+FooInMemoryRepository' has been registered.
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at UserQuery.Main() in C:\Users\TheGreatCO\AppData\Local\Temp\LINQPad5\_ntmafjyh\query_jcpvdk.cs:line 45

If I get all of the IFooRepository instances registered, I do get both. If I ask for just IFooRepository I get the last concrete implementation registered. If I ask for a specific concrete implementation, I get an InvalidOperationException.

Is it possible to resolve the concrete type from the dependency injector here or must I always resolve all of them, find which one I want and cast it to the concrete type?

Upvotes: 1

Views: 1582

Answers (1)

Tseng
Tseng

Reputation: 64307

Yes you can, but you have to register it explicitly.

In addition to

servicesBuilder.AddSingleton<IFooRepository, FooInMemoryRepository>();
servicesBuilder.AddSingleton<IFooRepository, FooOtherRepository>();

you also need

servicesBuilder.AddSingleton<FooInMemoryRepository>();
servicesBuilder.AddSingleton<FooOtherRepository>();

Upvotes: 1

Related Questions