ASP.NET Core的一个关键特性是它使用依赖注入(DI)。该框架围绕“符合容器”抽象设计,容许框架自己使用简单容器,同时还容许插入功能更丰富的第三方容器。git
针对多个服务注册实现的通常模式是常见的。大多数第三方DI容器都内置了这个概念。例如:Autofac;github
可是在Core 的DI容器中它是不支持的,好比:框架
public interface IBar {} public interface IFoo {} public class Foo : IFoo, IBar {} [Fact] public void WhenRegisteredAsSeparateSingleton_InstancesAreNotTheSame() { var services = new ServiceCollection(); services.AddSingleton<IFoo, Foo>(); services.AddSingleton<IBar, Foo>(); var provider = services.BuildServiceProvider(); var foo1 = provider.GetService<IFoo>(); // An instance of Foo var foo2 = provider.GetService<IBar>(); // An instance of Foo Assert.Same(foo1, foo2); // FAILS }
注册的Foo
是两个单例IFoo
和IBar
,但结果可能不是你所指望的。咱们实际上有两个Foo
“Singleton” 实例,每一个实例注册一次。ide
这个问题是由David Fowler在2年前提出的,但它已经解决了,有两种不太优雅的解决方案。函数
[Fact] public void WhenRegisteredAsInstance_InstancesAreTheSame() { var foo = new Foo(); // The singleton instance var services = new ServiceCollection(); services.AddSingleton<IFoo>(foo); services.AddSingleton<IBar>(foo); var provider = services.BuildServiceProvider(); var foo1 = provider.GetService<IFoo>(); var foo2 = provider.GetService<IBar>(); Assert.Same(foo1, foo); // PASSES; Assert.Same(foo2, foo); // PASSES; }
这里要注意: 必须在配置时对Foo进行实例化,而且必须知道并提供Foo的依赖项。在单例状况下,这可能比较适合,但它不是很灵活。ui
此外,若是你想Foo
成为每一个请求范围的单个实例(Scoped),那么这种方法就不行了,须要第二种方法spa
[Fact] public void WhenRegisteredAsForwardedSingleton_InstancesAreTheSame() { var services = new ServiceCollection(); services.AddSingleton<Foo>(); // We must explicitly register Foo services.AddSingleton<IFoo>(x => x.GetRequiredService<Foo>()); // Forward requests to Foo services.AddSingleton<IBar>(x => x.GetRequiredService<Foo>()); // Forward requests to Foo var provider = services.BuildServiceProvider(); var foo1 = provider.GetService<Foo>(); // An instance of Foo var foo2 = provider.GetService<IFoo>(); // An instance of Foo var foo3 = provider.GetService<IBar>(); // An instance of Foo Assert.Same(foo1, foo2); // PASSES Assert.Same(foo1, foo3); // PASSES }
为了将接口请求“转发”到具体类型,必须作两件事:设计
services.AddSingleton<Foo>()
services.AddSingleton<IFoo>(x => x.GetRequiredService<Foo>())