【问题标题】:Basic DI/IoC Questions - Architecture, SimpleInjector基本 DI/IoC 问题 - 架构、SimpleInjector
【发布时间】:2014-07-30 17:44:21
【问题描述】:

在针对以下类型的架构设置 IoC 容器时,我遇到了一个简单的问题。

在我的应用程序中,我有这样的层(从下到上):

  • Project.Domain
  • Project.Web(System.Web.Http等加上一些核心的HTTP类型逻辑)
    • 在这个项目中有一个 BaseController
  • Project.MicroServices 在 Web API 2.2 中实现 GET/POST 等。这些继承自 Project.Web 中的 BaseController,并引用 Project.Domain
  • Project.Logging 这是我尝试横切日志记录

当请求微服务层中的控制器时(GET、POST 等),SimpleInjector 使用属性注入将 ILogger 的实例添加到 BaseController。因此,微服务项目中的任何控制器都可以访问它。到目前为止效果很好。

这是我的问题:

我想让整个架构都可以访问日志记录,即使是在域层中,也不会破坏任何横切规则并保持事物解耦。我的想法可能是日志层可以订阅的域层发布的事件。但是,我离题了。我不明白的是如何让 SimpleInjector 将 Logger 实例传递给域(如果我应该,想法?)它是在应用程序启动时发生,还是仅在 Web 请求时发生?它应该是单例实例还是瞬态实例?以及这将如何最适合 Log4Net(我的架构可能过于复杂或过于复杂)。

我知道注册是在启动时发生的,但是获取实例呢?据我了解,我应该使用自动构造函数注入而不是使用 Container.GetInstance() 来获取实例,但是尽管我进行了大量阅读,但我仍然无法完全弄清楚它在 Web API 请求和 SimpleInjector 的 Web API 之外是如何工作的扩展。

另外,有些无关。我正在抽象出 Log4Net 功能,但我最近了解到我可能不应该这样做。考虑到这一点,我会喜欢一些关于如何将这一切联系在一起的建议。

【问题讨论】:

标签: c# .net asp.net-web-api dependency-injection simple-injector


【解决方案1】:

您的帖子有点含糊,而且充满了在没有更多上下文的情况下不容易回答的问题,但我会尽力而为。

我想让整个架构都可以访问日志记录,即使 在领域层

如果您有一个明确的日志抽象抽象,您可以使该抽象对应用程序可用并在整个应用程序中进行日志记录。

我正在抽象出 Log4Net 功能,但我最近了解到 我可能不应该这样做。

我不同意。我想你应该。如果可能,请防止使应用程序的核心依赖于 3rd 方组件,并且使用日志记录,这真的很容易做到。符合SOLID原则的define an abstraction很容易。别忘了,根据Dependency Inversion Principle,抽象应该是defined by the client。日志框架无法定义您需要的抽象。

但请确保不要像here 解释的那样陷入过多记录的陷阱。在大多数情况下,您不应该那么频繁地记录日志,而应该快速失败,并使用一些通用代码来为您记录日志,而不是在整个代码库中乱扔对您的 ILogger.Log 的调用。

如果您要发布事件,我认为这会大大减少您需要记录的时间,因为事件是完美的记录系统。只需将这些事件附加到表或磁盘上,您就知道在哪个时刻发生了什么。可能没有理由将更多信息写入日志。

我不明白的是如何让 SimpleInjector 通过 Logger 域的实例(如果我应该,想法?)

对此有很多意见。我和Mark Seemann 赞成anemic domain models with commands and events on top(或者我可以说我的命令和事件成为我的域模型?)。其他人在他们的领域对象中有更多的业务逻辑。这些对象需要一些服务,例如ILoanCalculator,并且您可能需要依赖注入,因为让这些域对象通过服务位置请求服务是very bad idea

但不要忘记,不仅仅是构造函数注入。对于您的域对象,您可以使用方法注入,将某些域方法所需的服务公开为方法参数:

public class Loan
{
    public void PayLoan(LoanPeriod periodToPay, ILoanCalculator calculator)
    {
        // ...
    }
}

由于您将拥有调用这些域方法的服务类(我可以说command handlers?),因此您可以对这些服务类应用构造函数注入并将依赖关系传递给域方法。

我知道注册是在启动时发生的,但是如何获取 实例?

在每个请求开始时检索实例(构建对象图)。

据我了解,我应该使用自动构造函数注入 而不是使用 Container.GetInstance() 来获取实例

没错。尽可能对从容器解析的任何服务使用构造函数注入。

但尽管我进行了大量阅读,但我仍然无法弄清楚如何 在 Web API 请求和 SimpleInjector 的 Web API 之外工作 扩展。

我不确定我是否理解这一点。几乎所有应用程序都是基于请求的,无论是 Web 应用程序、Windows 服务还是命令行工具。对于 Web 应用程序,请求以 Web 请求的形式从 Internet 传入。使用 Windows 服务,您有一个定期关闭的计时器,并且每个脉冲都可以视为一个新请求(或者您可能正在使用 SqlDependency 在这种情况下引发的事件是新请求的开始)。控制台应用程序可能只有一个请求,然后很快就死掉了。对于 Web 应用程序,Simple Injector 会隐式控制某些服务的生命周期,而 Windows 服务和后台进程则必须显式控制。使用 Simple Injector,LifetimeScopeExecutionContextScope 生活方式允许您定义一个显式范围来控制此类请求的对象的生命周期。 WebApiRequestLifestyle 实际上在后台使用 ExecutionContextScopeLifestyle 并开始和结束每个 Web API 请求的范围。

【讨论】:

  • 非常感谢您的周到回答!现在开始对我更有意义了。这给了我很多考虑和深思熟虑,但绝对应该让我开始。标记为答案。再次感谢!
猜你喜欢
  • 2011-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-10
  • 2020-03-05
  • 1970-01-01
相关资源
最近更新 更多