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

Pin*_*tel 1 .net dependency-injection .net-core

我有和 类I1,其中继承( :)并在 中实现。我想注册一个作用域依赖项,以便在单个作用域内引用任何接口时始终返回相同的对象。I2FooI2I1I2I1I2FooFoo

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

services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();
Run Code Online (Sandbox Code Playgroud)

我的定义如下:

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;
}
Run Code Online (Sandbox Code Playgroud)

功能性使用。

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();
}
Run Code Online (Sandbox Code Playgroud)

GetData()from会返回在相同范围内AnotherBar设置在 Bar- 的相同数据吗?SetData()

Ste*_*ven 5

这是使用 MS.DI 时需要注意的常见陷阱。这个陷阱被称为“撕裂的生活方式”。对于 MS.DI,每个注册都有自己的缓存。这意味着您的三个注册:

services.AddScoped<Foo>();
services.AddScoped<I1, Foo>();
services.AddScoped<I2, Foo>();
Run Code Online (Sandbox Code Playgroud)

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

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>());
}
Run Code Online (Sandbox Code Playgroud)

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

services.AddScoped<Foo>();
services.AddScoped<I1>(c => c.GetRequiredService<Foo>());
services.AddScoped<I2>(c => c.GetRequiredService<Foo>());
Run Code Online (Sandbox Code Playgroud)

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