【问题标题】:C# ILogger dependency Injection error: There is no argumentC# ILogger 依赖注入错误:没有参数
【发布时间】:2020-12-17 13:07:16
【问题描述】:

我有一个处理来自队列的消息的 Docker DotNet Core 控制台应用程序。

有一个名为 SimulationEngine 的类,我期待 ILogger 会被依赖注入自动传递

public class SimulationEngine
{
    ILogger<SimulationEngine> logger;

    public SimulationEngine(ILogger<SimulationEngine> logger)
    {
        this.logger = logger;
    }

这是创建实例的方式:

   public class RunsQueueProcessor : ...
   {
        public RunsQueueProcessor(..., ILogger<RunsQueueProcessor> logger)
        {
        }

        protected override async Task ProcessMessage(...)
        {
            this.logger.LogInformation(...);

            // Here DI is not working
            var engine = new SimulationEngine();
        

DI 可以很好地将记录器注入RunsQueueProcessor,但是当我尝试new SimulationEngine() 时它会失败并出现以下错误:

Error   CS7036  There is no argument given that corresponds to the required formal parameter 'logger' of 'SimulationEngine.Simui lationEngine(ILogger<SimulationEngine>)'

我如何告诉 DotNet 为该构造函数使用 DI?

--- 编辑 ---

我写这个问题是因为我正在研究 PoC,而且我不需要到处进行依赖注入。我只在进行单元测试以验证特定算法的少数地方需要它。 一个更具体的问题是,在使用 new 语句或手动实例化对象时,是否有办法配置 DotNet DI 框架以注入依赖项。

感谢所有 cmets 和答案,现在我对 DotNet DI 的工作原理有了更多了解。

【问题讨论】:

  • new SimulationEngine() 没有获得 DI 的好处,您手动新建。您需要在 new 语句中提供记录器,或者从您的服务集合中请求一个实例
  • SimulationEngine没有使用DI,需要在构造函数中添加参数,例如:public RunsQueueProcessor(..., ILogger&lt;RunsQueueProcessor&gt; logger, SimulationEngine engine)
  • 谢谢两位,我的问题更多是“什么时候可以,什么时候不能使用 DI”。我期待 dotNet 能够在任何地方做到这一点,似乎它只适用于像 ASP 控制器这样的东西。对吗?
  • 你对DI是什么有误解,建议你去读读。
  • 定义一个接口 ISimulationEngine 并实现 SimulationEngine,然后在你的处理器中注入 ISimulationEngine

标签: c# .net-core dependency-injection


【解决方案1】:

根据您的上一条评论,您希望更专注于解释依赖注入:其他选项,这是传统且正确的做法是:

  1. 定义一个标记接口,如ISimulationEngine
  2. SimulationEngine中实现接口ISimulationEngine
  3. IServiceCollection(在startup.cs中)注册接口
  4. RunsQueueProcessor 类的构造函数 中注入it,以便应用了解您要使用SimulationEngine

标记界面

public interface ISimulationEngine
{
    void DoSomthing();
}

实现接口的Service

public class SimulationEngine : ISimulationEngine
{
    private readonly ILogger<SimulationEngine> _logger;

    public SimulationEngine(ILogger<SimulationEngine> logger)  //<-- here you are injecting the registered Singleton of ILogger
    {
        _logger = logger;
    }

    public async void DoSomthing()
    {
        throw new NotImplementedException();
    }
}

假设另一个服务实现了该接口

public class AnotherService: ISimulationEngine
{
          public async void DoSomthing()
        {
            throw new NotImplementedException();
        }
}

startup.cs中服务的注册

public void ConfigureServices(IServiceCollection services)
{
    //...
    // this means whenever ISimulationEngine injected that class can use
    // SimulationEngine service

    services.AddTransient<ISimulationEngine, SimulationEngine>();
    //...
} 

请注意,您为SimulationEngine 注册了接口ISimulationEngine,但没有为AnotherService 注册接口,这也实现了相同的标记,但由于容器中的注册说每当你看到ISimulationEngine 注入时并使用 SimulationEngine

现在将 ISimulationEngine 注入您要使用的类中

public class RunsQueueProcessor
{
    private readonly ILogger<RunsQueueProcessor> _logger;
    private readonly ISimulationEngine _service;

    public RunsQueueProcessor(ILogger<RunsQueueProcessor> logger,  //<-- here AGAIN you are injecting the registered Singleton of ILogger
                              ISimulationEngine service            //<-- her you inject the Marker Interface so you can use any class implement this interface
                              )
    {
        _logger = logger;
        _service = service;
    }

    protected async Task ProcessMessage()
    {
        _logger.LogInformation("fdfdfd");

        await _service.DoSomthing();

        // Here DI is not working
        //var engine = new SimulationEngine();
    }
}

结论: 你可以想象像类说的注入的过程去检查DI容器,这个接口定义了哪个服务?!让我使用它

你可能会问 AdTransient 和 AddSingleton 有什么不同(也有 AddScoped)检查链接AddTransient, AddScoped and AddSingleton Services Differences

【讨论】:

  • 非常感谢@U8080,很清楚!最后一个问题。为什么 DotNet 在我的示例中没有注入 ILogger,但它确实在您的示例中注入了 ISimulationEngine?或者为什么它在 RunsQueueProcessor 中注入 ILogger 而不是在 SimulationEngine 中?谢谢!
  • @Carlos Garcia,很高兴听到它对您提出的问题很有用,因为您使用的是 DotNet Core 的默认 ILogger,它已经注册并设计用于通用类型 ILogger 所以这意味着你需要清楚地提到那个类。另一种选择是使用第三方 Logger,如 SeriLog,无需提及泛型类型即可使用。结果:这就是设计的方式。
  • @Carlos Garcia ,如果您问为什么在 C# 中使用 DI,答案是很多好处,但最重要的一个是解耦(使用 new 关键字消除)new 关键字正在制作消费者类依赖于服务器类。
  • 我想我现在明白了,DotNet Core 中的 DI 仅在框架实例化类时才有效。当您使用new手动实例化类时它不会这样做@
  • 感谢@U8080 的帮助!!现在我知道它在 C# 中是如何工作的 :)
猜你喜欢
  • 2020-12-08
  • 2020-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2016-01-26
  • 1970-01-01
相关资源
最近更新 更多