在分层架构中,应用层如何知道 Web URL?

问题描述

我目前正在开发一个使用分层架构(Web/应用程序/基础设施/域)的 .NET 5 应用程序。如果我要遵循洋葱/清洁架构模式,那么依赖项应该只向一个方向流动,例如:

Web -> 应用程序 -> 基础设施 -> 域

我现在发现自己需要从应用层发送几封包含特定前端 URL 的电子邮件。这意味着应用层会知道 Web 层,打破依赖流。

示例用例流程是:

  1. 用户发出请求,由 Web 层中的控制器处理
  2. 控制器调用应用层的处理程序
  3. 应用层使用基础设施层的电子邮件服务发送电子邮件

在第 3 步中,我在应用层,但需要 Web URL 来构建电子邮件正文。

我该如何解决这个问题?

解决方法

我最近在我的组织内解决了这个问题。在我们的例子中,我们有一个供整个公司使用的 API“市场”,然后是由紧密集成的客户端使用的反向代理,最后是 API 容器的内部负载平衡器。

这是我的 Web 层和应用程序层不应该知道的 3 层 URL 知识(即使在 Web 层它也不应该知道这一点,因为这将使我们的 Web 层承担多个责任,而不仅仅是一个路由器(例如通过 Mediatr))。

在基础架构中使用重写器

这就是 Z. Danev 的 answer 的全部内容。这是可行的,但您必须为每个层维护所有规则,并且每次重写都可能增加开销。此外,根据您返回的数据的复杂程度,这些规则可能会变得棘手。

一个有效的解决方案。根据您的组织,这可能是一件容易的事情,也可能是一件困难的事情,因为它由其他团队维护,需要工作票等等才能完成工作。

好吧,如果您不能或不想这样做,那么...

应用层依赖倒置和模式

免责声明:此解决方案对我们很好有效,但它确实有一个缺点:在某种程度上,您必须维护某些东西了解上面的层。所以请注意空客。

我上面描述的情况大致类似于您的问题,尽管可能更复杂(您可以做同样的事情,但要简化它)。在不违反架构原则的情况下,您需要提供一个(或多个)接口,该接口可以作为应用服务注入到您的应用层中。

我们将自己的 ILinkBuilderService 称为 LinkBuilderService 并创建了一个 ILinkBuilder,它本身可以通过具有单独 MarketPlaceBuilder 实现的 DI 容器进行连接。这些实现中的每一个都可以是 GatewayBuilder、{{1}} 等,并将根据从最外层代理到最内层代理的 Chain of ResponsibilityStrategy 模式进行排列。

通过这种方式,构建器会检查 Web 上下文(标头、请求等)以确定应该由哪一个来处理构建链接的责任。您的应用层(例如您的电子邮件发件人)仅使用关键数据调用链接构建服务接口,这用于生成面向客户端的 URL,而不会将应用层暴露给网络上下文。

在不涉及太多细节的情况下,这些构建器会在 HTTP 请求到达每个端点时检查 X-Forwarded-For 等标头、自定义标头以及代理提供的其他详细信息。责任链是关键,因为它允许应用层生成正确的 URL无论请求来自哪个层

那么这怎么能不打破单向流程呢?

好吧,您将这些构建器单向推入您的应用程序层。从技术上讲,它们确实会返回到 Web 层以获得上下文,但这是封装的。 这没问题,不会违反您的架构。这就是依赖倒置的全部内容。

,

考虑在 Web 基础架构级别(例如网关或负载均衡器)配置“众所周知的 url”,以便您可以在电子邮件中包含“mycompany.com/user-action-1”,这将转换为正确的端点您的网络应用。