在ASP.NET中使用dependency injection和工厂模式传递服务

我正在使用ASP.NET Core,我知道框架已经提供了这样的Logging机制,但是使用它来说明我的问题。

我正在使用一种Factory模式来构建Logger类,因为我不知道日志记录的类型(因为它存储在DB中)。

ILogger合同

Log(string msg) 

然后,在根据从DB传递的参数创建Logger之后,LoggerFactory将返回ILogger:

 public class LoggerFactory { public static Contracts.ILogger BuildLogger(LogType type) { return GetLogger(type); } //other code is omitted, GetLogger will return an implementation of the related logger 

现在,当我需要使用Logger时,我必须这样做:

  public class MyService { private ILogger _logger public MyService() { _logger = LoggerFactory.BuildLogger("myType"); } 

但是,我打算在没有任何实例化的情况下保留我的类,我需要在MyService中使用Constructor DI,我需要在Startup上注入所有依赖项:

  services.AddTransient (); 

但这不起作用,我们需要通过一个具体的实现。 如何使用DI来完成这项工作,是否有更好的方法来实现它?

您的方法中存在一些错误:

  • 您的服务依赖于具体的LoggerFactory类型,这是一种dependency injection原则违规。
  • 执行此额外初始化可能会使构建对象图不可靠,而注入构造函数应该很简单 。
  • 它隐藏了ILogger是您的消费者所依赖的真实服务这一事实。 这使得系统更难以测试,更难以维护,并使对象图分析变得复杂。
  • 使用工厂是一种气味,因为工厂几乎不是正确的解决方案 。

相反,您的服务应如下所示:

 public class MyService { private ILogger _logger; public MyService(ILogger logger) { _logger = logger; } } 

这大大简化了依赖ILogger所有消费者。 这也意味着为MyService获取正确的ILogger将成为Composition Root的责任,这是获得这些知识的正确位置。

但是,它确实意味着您可能需要从ASP.NET Core的内置DI容器转移到function更丰富的DI库,因为内置容器无法为ILogger进行上下文感知注册库自动连接其他构造函数依赖项。

使用ASP.NET Core DI容器,您只能使用委托来手动连接服务。 例如:

 services.AddTransient(c => new MyService( BuildLogger(typeof(MyService).Name), c.GetRequiredService(), c.GetRequiredService());