Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 作用域/瞬态依赖项注入确保返回接口和实现的相同实例_C#_Asp.net Core_Dependency Injection_.net Core - Fatal编程技术网

C# 作用域/瞬态依赖项注入确保返回接口和实现的相同实例

C# 作用域/瞬态依赖项注入确保返回接口和实现的相同实例,c#,asp.net-core,dependency-injection,.net-core,C#,Asp.net Core,Dependency Injection,.net Core,请随意为这个问题建议一个更好的标题。我想不出一个好名字来描述这个问题 我需要在启动时通过依赖注入来访问一个类。该类不仅应通过其具体实现可用,还应通过其实现的接口可用。我需要确保它是通过两次注入返回的同一个对象实例 现实世界中的场景让我想到了singleton案例,它是一个用于提供接口(ISTOR)的抽象的nuget,多个nuget持有具体的实现(DBStore、Redistore)。当我尝试为每个商店实现实施健康检查时,我可以注入IStore,但不能注入具体的实现。我想使用一些在具体实现中初始化

请随意为这个问题建议一个更好的标题。我想不出一个好名字来描述这个问题

我需要在启动时通过依赖注入来访问一个类。该类不仅应通过其具体实现可用,还应通过其实现的接口可用。我需要确保它是通过两次注入返回的同一个对象实例

现实世界中的场景让我想到了singleton案例,它是一个用于提供接口(ISTOR)的抽象的nuget,多个nuget持有具体的实现(DBStore、Redistore)。当我尝试为每个商店实现实施健康检查时,我可以注入IStore,但不能注入具体的实现。我想使用一些在具体实现中初始化和修改的变量(这就是为什么我需要两个注入都使用相同的实例)。由于商店(希望)被用作单身人士,所以它起了作用。我并不是说有一个现实世界中的场景是有范围的和暂时的。我只是好奇,如果他们不是单身汉,这是否可能

下面的代码描述了我是如何处理单例的

引导我使用单例解决方案的方式:

具有此接口:

public interface ITestInterface
{
  string ReturnAString();
  int ReturnAnInt(); 
}
这是具体的实施

public class TestImplementation : ITestInterface
{
  private int counter = 0;
  public string ReturnAString() {return "a string"; }
  public int ReturnAnInt() { return counter++; }
}
它们被用于两种(比方说)服务。一个需要在构造函数中注入接口,另一个需要具体的实现

Startup.ConfigureServices方法中的尝试和错误,用于在两种情况下注入相同的实例:

尝试1:

// only ITestInterface is injected but not TestImplemenation
services.AddSingleton<ITestInterface, TestImplementation>();
//只注入ITestInterface,而不注入TestImplementation
services.AddSingleton();
尝试2:

//only TestImplementation is injected (DI does not recognize it implements the Interface)
services.AddSingleton<TestImplementation>();
//只注入TestImplementation(DI不识别它实现了接口)
services.AddSingleton();
尝试3:

// both are injected but they are not singleton any more (counters increment independently)
services.AddSingleton<ITestInterface, TestImplementation>();
services.AddSingleton<TestImplementation, TestImplementation>();
//两者都被注入,但它们不再是单例(计数器独立递增)
services.AddSingleton();
services.AddSingleton();
尝试4:

TestImplementation instance = new TestImplementation();
services.AddSingleton<ITestInterface>(instance);
services.AddSingleton(instance);
//services.AddSingleton<TestImplementation>(instance);
TestImplementation实例=新建TestImplementation();
services.AddSingleton(实例);
services.AddSingleton(实例);
//services.AddSingleton(实例);
嗯,在第4次尝试中,我对两种注射都有相同的实例

现在让我们假设测试实现需要注入一些设置(例如连接)

我可以编写一个扩展方法,从配置中获取设置,并将其传递给singleton实例

TestImplementation instance = new TestImplementation(Configuration.GetTestSettings());
services.AddSingleton<ITestInterface>(instance);
services.AddSingleton(instance);
TestImplementation实例=新的TestImplementation(Configuration.GetTestSettings());
services.AddSingleton(实例);
services.AddSingleton(实例);


那么,我如何使用相同的设置和作用域或瞬态实现两个注入都是相同的实例呢?因为我不认为我可以在那里手工/编码创建实例。

基本上,您希望将单个服务实现类型注册为两个服务契约(具体类+接口)。这是非常常见的情况,但不幸的是,默认的Microsoft DI容器(ServiceCollection)功能有限,我认为实现所需效果的唯一方法是使用factory委托:

services.AddScoped<TestImplementation>();
services.AddScoped<ITestInterface>(s => s.GetRequiredService<TestImplementation>());
services.addScope();
services.addScope(s=>s.GetRequiredService());
尽管这样做会带来一些额外的运行时成本,但我强烈建议使用一个功能齐全的DI容器,如Autofac或Ninject,如果我没有错的话,它可以通过使用

但是,由于公司的政策,向第三方库添加依赖项通常是不可取的,甚至是禁止的

在这种情况下,我认为你最好创建一个工厂。例如:

public class TestFactory
{
    public ITestInterface Create(string flavor)
    {
        if (flavor == "concrete")
        {
            return new TestImplementation();
        }
        else
        {
            return new OtherTestImplementation();
        }
    }
}
然后,在您的
Startup.cs
中,您将像这样注入它:

services.AddSingleton<TestFactory>();
services.AddSingleton();
请注意,
ITestInterface
服务寿命最终取决于您将对
Create(…)
方法调用结果的引用存储在何处。

使用将能够使用
AsSelf()添加接口和实现接口。
方法:

container.RegisterType<TestImplementation>.As<ITestInterface>().AsSelf();

回答得好!请参阅附加内容:我有类似的要求,我看到了Andre Lock的博客文章,其中描述了如何使用ASP.NET Core DI实现同样的要求。这里是链接-
container.RegisterType<TestImplementation>.As<ITestInterface>().AsSelf().SingleInstance();