使用 Clean Architecture 从 ApplicationCore 库中的实体引用 Infrastructure 库中的 ApplicationUser

Posted

技术标签:

【中文标题】使用 Clean Architecture 从 ApplicationCore 库中的实体引用 Infrastructure 库中的 ApplicationUser【英文标题】:Referencing ApplicationUser in the Infrastructure library from an entity in the ApplicationCore library using Clean Architecture 【发布时间】:2019-05-08 20:57:13 【问题描述】:

我正在关注Microsoft Architecture Guide 创建一个 ASP.NET Core Web 应用程序。

该指南实现了非常简单的干净架构模式。

如果您查看使用干净架构模式的示例项目,您会看到有一个包含 ApplicationUser.cs 类的 Infrastructure/Identity 文件夹。

我的问题: 我正在使用实体框架,我在 ApplicationCore 类库中的一个业务实体需要包含一个 ApplicationUser 列表。 ApplicationCore 库不应引用任何其他项目。它包含所有接口和业务实体。如何在我的 Infrastructure/Identity 项目中保留 ApplicationUser 类,并且仍然在 ApplicationCore 项目中的一个业务实体中使用它而不违反规则。

我知道一种解决方案是不在我的基础架构项目中存储 ApplicationUser 实体。但是,我觉得它应该存在,因为它在实现 IdentityUser 时将始终依赖于 Identity。

【问题讨论】:

它在基础设施中,因为 ApplicationUser 继承了 IdentityUser 的形式,即 身份验证,身份验证是基础设施问题。您永远不应该将身份验证放入您的核心域,因为(几乎)世界上没有任何企业拥有User 无处不在的语言、流程等。当您拥有一家商店时,您就拥有了客户,但没有用户。用户是一个技术术语。用户可能与客户相关(即用户 ID 和客户 ID 可能相同或通过 1:1 或 n:1 关系连接)。因为可以删除或阻止用户,但保留客户 另请参阅 GitHub 上的 this issue 以了解它的说明。您应该记住,eShopOnContainers 不仅是一个干净的架构,还涉及领域驱动设计和使用无处不在的语言的 ddd 等主题(这是公司的领域专家所说的,比如销售人员、市场营销、不是软件开发人员)是必要的。从技术上讲,用户只是识别/验证用户身份的一种手段,因此客户永远不会与用户相同 因为您知道,当通过传真或电话接受订单时,您可以拥有没有登录的客户 【参考方案1】:

用户是一个实体,它应该在核心层。

但您不应在核心层中使用 ApplicationUser : IdentityUser,因为它与 ASP.NET 标识相关联。核心层不应该知道哪些技术将实现该领域。

如果明天您想使用另一个库进行用户管理怎么办?这不是核心层关心的问题。

您可以做的是在核心层使用接口或基本用户类,让基础设施层担心库选择决策。

【讨论】:

怎么会有人这样做?? ApplicationUser 是实体,所以它应该在核心中(我同意),但如果我不这样做,它必须扩展 IdentityUser 原因,所以我不能在 AspIdentityDbContext 中使用它......我意识到如果你正在处理的问题对于任何具有 DbContext(如 AspCore.Identity 或 IdentityServer4)的包,您最终将在核心中引用这些包,因为最终您将使用它们的实体作为核心实体的一部分,否则您甚至无法使用核心实体进行迁移跨度> 【参考方案2】:

在清洁架构中:

应用程序核心类型

• 实体(持久化的业务模型类)和聚合

• 接口

• 服务

• DTO

• 规格

• 例外情况

基础设施类型

• EF Core 类型(DbContext、迁移)

• 数据访问实现类型(存储库)

• 特定于基础架构的服务(FileLogger、SmtpNotifier 等)

所以 ApplicationUser.cs 是一个实体,它应该在 Application Core 中

【讨论】:

Microsoft 编写了有关清洁架构的完整手册,并在我上面的链接中提供了一个示例项目来引用它,并且他们在 Infrastructure 项目中抛出了 ApplicationUser 类。知道为什么吗? 所以在 ApplicationCore 项目中拥有 ApplicationUser 并安装 Microsoft.AspNetCore.Identity.EntityFrameworkCore 以便它可以从 IdentityUser 继承没有任何问题? 我的意思是,如果您使用 ApplicationUser.cs 作为持久实体,您会将其移至 Application Core。 在 eShop 示例中,他们将 ApplicationUser.cs 放在基础架构中,我认为这是不正确的。让我们向社区询问这个 投反对票,因为我认为它不能回答问题。【参考方案3】:

这也是我自己的问题,它似乎以某种方式基于意见。我最终得出结论,如果您依赖于其中指定了 DbContext 的任何包,那么您将在您的核心项目中引用此包。

例如,我正在使用 AspCore.Identity 和 IdentityServer4,我有很多 DbContexts,但现在让我们说两个:

ConfigurationDbContextIdentityDbContext 以及这两个上下文控制两个实体(只是为了让事情变得更容易)客户端(OAuth2 客户端)和 IdentityUser 所以现在我已经将所有这些作为基础设施,但现在我想拥有我的自己的核心实体 ApplicationUser 和 ApplcationClient 那么我怎样才能将它们放在我的核心中而不让它们继承他们的父母,这样我就可以查询它们,保存它们或从任何来源检索它们。

我不知道完美的答案,但我最终将这些实体放在核心中并在我的核心中引用 NuGet 包,这显然不遵循干净的架构角色,但我找不到比这更好的解决方案那个。

【讨论】:

以上是关于使用 Clean Architecture 从 ApplicationCore 库中的实体引用 Infrastructure 库中的 ApplicationUser的主要内容,如果未能解决你的问题,请参考以下文章

从 UI 向 UseCase Android Clean Architecture 传递太多参数

每种存储库方法的Android Clean Architecture UseCase?

android clean architecture 已停止运行啥意思

使用Android MVP Clean Architecture实现交互者

Android Clean Architecture中的登录流程

在 Clean Architecture 中,UI 代码在哪一层?