【问题标题】:Injecting logger from DI to object created with factory将记录器从 DI 注入到使用工厂创建的对象中
【发布时间】:2022-01-16 01:03:00
【问题描述】:

我需要将记录器(ILogger)添加到 MyDbConnection 的现有对象中,该对象是从工厂创建的,该工厂与 MyOptions 类一起注册在 NET Core DI 中

public class MyFactory : IMyFactory
{
    private readonly MyOptions _options;

    public MyFactory(MyOptions options)
    {
        _options = options;
    }

    public MyDbConnection CreateDbA() => new MyDbConnection(_options.ConnStrA);
    public MyDbConnection CreateDbB() => new MyDbConnection(_options.ConnStrB);
    public MyDbConnection CreateDbC() => new MyDbConnection(_options.ConnStrC);
}

工厂然后被注入到服务中,然后使用它来创建对象并做一些事情

public class MyService : IMyService
{
    public MyService(IMyFactory factory)
    {
        var a = factory.CreateDbA();
        var b = factory.CreateDbB();
        a.DoSomething();
        b.DoSomething();
    }
}

MyDbConnection 如下所示:

public class MyDbConnection
{
    private string connStr;
    //private ILogger logger;

    //public MyDbConnection(string connStr, ILogger logger)
    public MyDbConnection(string connStr)
    {
        this.connStr = connStr;
        //this.logger = Logger;
    }

    public void DoSomething()
    {
        //logger.LogWarning();
    }
}

问题是我不能只添加 ILogger 并从 DI 容器中注入它,因为工厂正在使用“新”来创建 MyDbConnection,而不使用 DI。我目前唯一的解决方案是使用静态记录器而不是注入一个,但这似乎是一个糟糕的解决方案。还有其他方法吗?应该怎么做才合适?

【问题讨论】:

  • 您可以配置/使用 DI 来获取 MyDbConnection 的新实例。如果这不是您想要的,那么只需将 ILogger 添加到您的工厂:public MyFactory(MyOptions options, ILogger logger) 并将注入的记录器传递到新的连接中。
  • 一个小故事:您的连接是否以某种方式处理?或者你只是展示一个省略处理的示例代码?
  • @MetroSmurf 将 ILogger 添加到工厂也是我的想法之一,但毕竟我决定尝试寻找更好的解决方案
  • @WiktorZychla 这只是示例代码,基于现有的,我已经将其简化并显示我遇到的问题

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


【解决方案1】:

需要重构设计才能获得所需的行为。

首先应重构MyDbConnection 以依赖于适当的记录器

例如

public class MyDbConnection {
    private string connStr;
    private ILogger logger;

    public MyDbConnection(string connStr, ILogger<MyDbConnection> logger) {
        this.connStr = connStr;
        this.logger = logger;
    }

    public void DoSomething() {
        logger.LogWarning();
    }
}

然后工厂重构为使用ActivatorUtilities 来初始化并通过注入的服务提供者注入必要的依赖项。

public class MyFactory : IMyFactory {
    private readonly MyOptions options;
    private readonly IServiceProvider services;

    public MyFactory(MyOptions options, IServiceProvider services) {
        this.options = options;
        this.services = services;
    }

    public MyDbConnection CreateDbA() => ActivatorUtilities.CreateInstance<MyDbConnection>(services, options.ConnStrA);
    public MyDbConnection CreateDbB() => ActivatorUtilities.CreateInstance<MyDbConnection>(services, options.ConnStrB);
    public MyDbConnection CreateDbC() => ActivatorUtilities.CreateInstance<MyDbConnection>(services, options.ConnStrC);
}

在上面的示例中,与之前手动初始化时一样提供了特定的依赖项。所有其他依赖项(如记录器) 将通过服务提供者解析并在初始化时注入目标类。

这样可以保持依赖注入,避免手动初始化MyDbConnection

【讨论】:

  • 将 IServiceProvider 暴露给工厂类怎么样?这不是一件坏事吗?因为将来有人可以使用它来手动解析项目?
猜你喜欢
  • 2016-07-12
  • 2018-03-31
  • 1970-01-01
  • 2011-09-10
  • 2010-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多