无法从IServiceProvider获取具体实现类型?依赖注入问题咨询
这个问题在使用Microsoft.Extensions.DependencyInjection时挺常见的,我来帮你理清楚原因和对应的解决方案:
为什么直接获取具体类型会报错?
当你用servicesBuilder.AddSingleton<IFooRepository, FooInMemoryRepository>()注册服务时,DI容器只建立了接口IFooRepository到实现FooInMemoryRepository的映射关系,并没有把FooInMemoryRepository本身作为一个独立的服务条目注册进去。所以当你调用services.GetRequiredService<FooInMemoryRepository>()时,容器找不到对应的服务注册,自然会抛出InvalidOperationException。
解决方案:显式注册具体类型
要直接获取具体实现类,你需要把具体类型也注册到容器中,同时保证接口和具体类指向同一个实例(如果是单例的话)。
单一实现的场景
如果只有FooInMemoryRepository这一个实现,你可以这样注册:
// 先注册具体类型为单例 servicesBuilder.AddSingleton<FooInMemoryRepository>(); // 再将接口绑定到这个具体实例 servicesBuilder.AddSingleton<IFooRepository>(sp => sp.GetRequiredService<FooInMemoryRepository>());
这样无论是通过GetRequiredService<IFooRepository>()还是GetRequiredService<FooInMemoryRepository>(),拿到的都是同一个单例实例,不会报错。
多个实现的场景
当你注册了多个IFooRepository的实现时,同样需要先注册每个具体类型,再绑定到接口:
// 注册所有具体实现为单例 servicesBuilder.AddSingleton<FooInMemoryRepository>(); servicesBuilder.AddSingleton<FooDatabaseRepository>(); // 分别将接口绑定到对应的具体实例 servicesBuilder.AddSingleton<IFooRepository>(sp => sp.GetRequiredService<FooInMemoryRepository>()); servicesBuilder.AddSingleton<IFooRepository>(sp => sp.GetRequiredService<FooDatabaseRepository>());
此时:
- 调用
services.GetServices<IFooRepository>()会返回两个实例(和注册顺序一致) - 调用
services.GetRequiredService<FooInMemoryRepository>()或services.GetRequiredService<FooDatabaseRepository>()都能直接拿到对应的具体实例,无需遍历强转
额外简化写法
如果你不想分开注册,也可以直接创建实例后,把同一个实例同时注册为具体类型和接口的服务:
var repo = new FooInMemoryRepository(); servicesBuilder.AddSingleton<FooInMemoryRepository>(repo); servicesBuilder.AddSingleton<IFooRepository>(repo);
这种方式更直接,效果和前面的写法完全一致。
总结一下:完全可以直接解析具体类型,不需要遍历实例强制转换,只要你在注册时显式把具体类型也添加到DI容器中即可。
内容的提问来源于stack exchange,提问作者Pete Garafano

