具有继承接口的 .NET Core 依赖注入

.NET Core Dependency Injection with inherited interface

我有 I1I2 和 Class Foo,其中 I2 继承了 I1I2:I1) 和 I2Foo 中实现。我想注册一个范围内的依赖项,以便在单个范围内引用任何接口时始终 return 相同的 Foo 对象。

我尝试使用以下注册进行此操作,但它在同一范围内产生了 Foo 的三个不同实例:

services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();

我的定义如下:

interface I1
{
    GetData();
}
    
interface I2 : I1
{
    string Data { set; }
}

class Foo : I2
{
    private string myData;

    public string Data { set => myData = value; }

    public string GetData() => this.myData;
}

功能使用。

class Bar
{
    private I2 _i2;
    public Bar(I2 i2) => _i2 = i2;

    public void SetData() => _i2.myData = "My Data";
}

class AnotherBar
{
    private I1 _i1;
    public AnotherBar(I1 i1) => _i1 = i1;

    public string GetData() => _i1.GetData();
}
来自 AnotherBar

GetData() 将 return 在相同范围内设置在 Bar-SetData() 的相同数据?

这是使用 MS.DI 时需要注意的常见陷阱。这个陷阱叫做Torn Lifestyle。在 MS.DI 的情况下,每个注册都有自己的缓存。这意味着您的三个注册:

services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();

每个都有自己的缓存和自己的实例。所以这意味着以下断言成立:

using (var scope = provider.CreateScope())
{
   Assert.AreSame(scope.GetService<I1>(), scope.GetService<I1>());
   Assert.AreSame(scope.GetService<I2>(), scope.GetService<I2>());
   Assert.AreNotSame(scope.GetService<I1>(), scope.GetService<I2>());
}

要解决此问题,您必须将注册重写为以下内容:

services.AddScoped<Foo>();
services.AddScoped<I1>(c => c.GetRequiredService<Foo>());
services.AddScoped<I2>(c => c.GetRequiredService<Foo>());

在这种情况下,每个注册仍然有自己的缓存,但由于第二个和第三个请求原始 Foo 服务,这确保所有三个注册 return 同一范围内的同一实例.