【问题标题】:One web API route that needs multiple services一个需要多个服务的 Web API 路由
【发布时间】:2019-02-22 22:36:07
【问题描述】:

我正在构建一个使用工作流的网站。基本上,工作流可以包含任务以及工作流中发生的所有事情的历史记录。当有人通过 UI 将任务分配给其他人时,必须发生两件事:

  • 必须将任务分配给新的受让人
  • 必须创建工作流历史记录条目

为此,我有一个“TaskController”Web API 和一个“Assign”路由,该路由需要任务 ID 和新的受理人用户名。

现在,我不知道该怎么做。事实上,我有一个“TaskService”,我可以在其中添加一个“Assign”方法,但我不确定这个方法应该做什么。我确定它需要分配任务,但是工作流历史的创建呢?对我来说,这样做是“WorkflowService”的责任。此外,可能在某些情况下我不想创建历史记录,但是当我使用“TaskService”时,它总是会这样做(除非我在方法中添加了“createHistory”参数但我没有不想那样做)。

我想到的另一个解决方案是在 Web API 路由中调用这些不同的服务。像这样的东西(在伪代码中):

_taskService.AssignTask(...);
_workflowService.CreateHistory(...);

这似乎是一个更好的解决方案,但问题是这两个方法写入数据库,所以我应该使用事务:

using (_dbContext.Transaction) {
   _taskService.AssignTask(...);
   _workflowService.CreateHistory(...);
}

这可行,但我觉得 Web API 路由有很多逻辑......

我在 Google 上搜索了一段时间,但没有找到任何可以帮助我做出决定的东西。对我来说,服务应该只执行特定的操作,因此“TaskService”不应该添加工作流历史记录条目。但是,Web API 路由中不应包含大逻辑(因此,它不应创建事务)。

有没有人知道一种模式或什么可以帮助我解决这个问题?

【问题讨论】:

    标签: asp.net-core entity-framework-core asp.net-core-webapi


    【解决方案1】:

    您在问一个无法明确回答的问题。这完全取决于您希望如何构建您的应用程序,因此只有您可以做出决定。这里没有一成不变的对与错。

    一般而言,对于审计跟踪等低级事物,您希望将其抽象出来。您不必考虑在审计跟踪中添加一些内容:它应该会发生。这听起来像是将其集成到您的任务服务(以及任何其他需要此功能的服务)中的论据。不过有两点需要注意。首先,它仍然可以是“工作流服务”,只是只有其他服务与之交互,而不是您的应用程序本身。其次,服务不必以绝对最严格的方式只做一件事。您的任务服务“只做一件事”,因为它只适用于任务,但它完全可以接受其他服务来促进该目标。

    也就是说,在您的操作中独立调用每个服务的替代方法在技术上没有任何问题。虽然,如果服务是真正独立的,那么协调数据库事务将是困难的,如果它们不是,那么您就没有构建好的服务。这实际上是更全面地看待服务范围的另一个原因。如果添加任务需要添加工作流,并且这些事情需要以事务方式一起完成,那么您必须以相同的方法完成它们,这意味着添加工作流项是您的任务服务的功能,至少以抽象的方式。

    就模式而言,微服务架构基本上就是您在此处构建的内容,只是无需创建单独的应用程序。但是,遵循真正的微服务架构将迫使您真正描述您的服务范围。如果您查看该模式,您会发现每个微服务都是一个离散的功能单元,但并未禁止与其他服务交互以协调工作。例如,购物车服务可能需要与库存服务和定价服务一起使用。它仍然只做一件事:管理购物车。然而,为了实现这一点,还需要做其他工作——其他服务负责的工作。因此,他们必须协调才能完成工作。

    【讨论】:

    • 我在这里看到了你的观点。但是,我担心在另一个服务中使用一个服务很容易在某些时候创建循环依赖。在这里,接受任务将创建工作流历史记录,但启动工作流可能会创建任务。所以 TaskService 将需要 WorkflowService 他们将需要 TaskService ..
    • 循环依赖实际上只是应用程序设计不正确的线索。如果两个事物相互依赖,那么它们就不是两个独立的事物。这是一种逻辑上的不一致,您试图分解不可分割的功能。如果任务需要创建工作流,那么您可能需要一些可以由您的任务服务使用的基本“工作流”服务以及仅用于此目的的独立工作流服务。无论如何,这就是您的服务设计发挥作用的地方,只有您对自己的领域有足够的了解才能做出决定。
    【解决方案2】:

    在您的场景中,您可以使用两种方式创建历史记录

    1. 使用数据库触发器
    2. 通过覆盖 EF 存储库中任务实体的 DatabaseContext.Save() 方法

    这样,您只需从您的 Web API 方法中调用一次“_taskService.AssignTask(...)”,即可创建历史记录。选择审计跟踪方法将取决于您的应用程序架构(即,您如何创建服务和存储库、您的实体等)。如果您的应用程序设计不太复杂,以上两种方法中的任何一种都可以无缝地工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 1970-01-01
      • 1970-01-01
      • 2017-05-16
      • 2013-10-15
      • 2011-01-29
      • 1970-01-01
      相关资源
      最近更新 更多