干净的架构——合并存储库模式

目录

介绍

目的

范围

先决条件

解决方案\环境设置

代码库

SQL数据库脚本

Visual Studio Extension

组件和Nuget包

清洁架构的快速解释

核心(领域和应用程序)

基础设施

用户界面应用程序

Visual Studio——解决方案结构

正在运行的Blazor应用程序

添加现有数据库实体和数据库文本

实体

DBContext

连接字符串(API项目)

干净的架构——我们解决方案的主要层

领域(类库)

应用程序——用例\业务逻辑(类库)

应用层——接口

DTO

已启用Swagger(启动设置API)

Polly重试策略

测试Polly

日志记录(服务器端)

单元测试——MSTest\Faker\Bogus


介绍

本文档详细介绍了如何将存储库模式合并到干净的体系结构模式中。它涉及现有MVC模式(日志记录、单元测试、DIEF Core等)中的许多常见方面。

目的

产品架构文档(PAD)提供了有关如何将数据库优先方法集成到干净架构方法中的全面架构概述——涉及哪些组件以及它们如何相互关联。

范围

PAD的范围是传达使用存储库模式生成干净架构模式所需的概念。

先决条件

  • 了解MVC或DDD体系结构模式
  • 了解数据库优先方法(存储库模式)
  • 了解SQL Server——运行SQL脚本
  • .NET Core\6的知识
  • SQL Server(包括SSMS)和Visual Studio已安装(免费+版本)
  • MSTest的基本知识

解决方案\环境设置

代码库

使用此链接 https://github.com/Bert0Neill/CleanArchitectureDemo.git 克隆代码存储库。

SQL数据库脚本

可以使用此SQL脚本链接下载测试数据库。

Visual Studio Extension

从此处下载并安装Visual Studio EF Core Power Tools 扩展——EF Core Power Tools - Visual Studio Marketplace

组件和Nuget

为了使解决方案尽可能逼真,我使用了以下包和组件,这些包和组件当前将用于现有体系结构模式——这些包和组件已合并到使用它们的解决方案项目中。

  • Faker\Bogus
  • MOQ
  • MSTest
  • IHttpFactory
  • Http Polly (API retries)
  • EF Core 6
  • SQL Server database
  • EF Power Core Tools
  • Middleware (Exception Handling)
  • Logging (file based)
  • GuardRails
  • Blazor WASM
  • Benchmark.Net (performance)
  • AutoMapper
  • Swagger UI

清洁架构的快速解释

清洁架构模式的概念已经存在了十多年,最初由罗伯特·马丁(更广为人知的名字是鲍勃叔叔)构思。鲍勃叔叔的关键词是可以互换的。在下图中,蓝色圆圈上的所有内容都是可以互换的,例如,UI可以从Angular换成React,或者数据库可以从Oracle迁移到MySQL,底层中的任何内容都不需要更改。

将所有接口(基础结构和应用程序)放在一个项目中的概念将使单元测试和模拟变得更加容易。

但清洁架构背后的主要理由是MVC不扩展或允许层的相同松散耦合。在清洁体系结构中,依赖项仅面向内部(这满足来自SOLID主体的DI)。在MVC中,模型视图充当UI和控制器层合二为一,这可能会变得非常大且难以测试(因为紧密耦合)。MVC已经为软件行业服务了20多年,但该行业希望在未来20年内采用一种新的更精简的架构模式——一种可扩展、可互换\解耦的架构模式。

核心(领域和应用程序)

  • 应用层是(核心的)顶层或父层,仅依赖于域层。基础结构或UI等其他层将取决于应用程序。
  • 应用程序包含“接口”、“业务逻辑”等。
  • 域项目主要包含“实体”、自定义异常、枚举等。

基础设施

基础设施处理数据库外部 API 调用缓存等。基本上,基础设施处理所有外部资源。基础结构取决于应用程序内部的接口。由于依赖关系反转,我们的应用程序将是松散耦合的,这使得测试变得容易。

用户界面应用程序

UI应用程序使用应用程序核心来生成结果。在实时场景中,UI应用程序从不依赖于基础结构层,但是我们必须在注册服务依赖注入的情况下将基础结构层引用到UI项目中。因此,UI项目不应使用依赖注入以外的基础结构层的任何代码。

Visual Studio——解决方案结构

解决方案被拆分为解决方案文件夹,在每个文件夹中,都有一个项目(根据大小或复杂性,每层可以有多个项目,因此将一个层拆分为多个项目可能更有意义,维护明智):

  • CleanArchitecture.Domain——“应用程序核心”——类库模板项目
  • CleanArchitecture.Application——“应用程序核心”——类库模板项目
  • CleanArchitecture.Infrastructure——“基础结构”——类库模板项目
  • CleanArchitecture.Api——“API”——一个Web API模板项目
  • CleanArchitecture.Blazor——“Web UI”——Web UI模板项目
  • CleanArchitecture.UnitTests——“单元测试”——类库模板项目

正在运行的Blazor应用程序

下图显示了最终的UI屏幕(即从客户端Web应用程序到接口控制器的调用),而API控制器又调用应用程序服务(用例\业务逻辑),后者调用相应的基础结构类来执行外部任务。

添加现有数据库实体和数据库文本

实体

数据库实体将保存在域项目本身中,右键单击域项目并从上下文菜单中选择EF Core Power Tools,然后选择反向工程

然后,系统将提示您选择要对数据库模型进行反向工程的数据库。

接下来,您可以选择相应的数据库表来为其生成实体:

确保仅从要生成的内容下拉列表中选择实体类型,因为我们只希望创建实体,而不是Domain项目中的DBContext。输入创建实体的路径,右键单击Domain项目时,命名空间应该是正确的。

DBContext

右键单击基础结构项目,然后再次选择“EF Core Power Tool,对(进入Application项目)进行反向工程 DBContext

确保从下拉列表中选择DbContext,并输入要生成 DBContext的路径:

然后,这将为相应项目中的实体和DBContext生成以下结构:

连接字符串(API项目)

连接字符串放置在 API项目的Programs中,因为我们正在使用该Application项目,而该项目又需要注入将使用DBContext

将对DBContextMusicContext来自基础结构项目)的引用添加到 Program.cs 类中,因为它只允许在Application类中执行DI

应用设置文件中指向连接字符串的条目:

干净的架构——我们解决方案的主要层

清洁架构方法非常多样化,因为它可以满足您希望使用的任何设计模式(例如,带有装饰器的工厂),但是在我们的示例中,我使用的是通用存储库模式方法。

领域(类库)

域项目将托管企业范围的实体\模型、自定义异常、枚举等,但它没有依赖项、没有项目或类引用、没有业务逻辑等。

提示——术语Entity来自SQL Server “Id实体属性——这意味着实体必须具有主键。

应用程序——用例\业务逻辑(类库)

将这些服务视为应用程序的业务逻辑\用例层,从UI传递到域,并执行解决方案所需的必要应用程序逻辑。应用层将使用域模型,但使用基础结构层与外部世界通信,从而使用这些结果来执行其业务逻辑(对来自多个基础架构调用的结果进行切片和切块,这些结果又作为(例如)DTO传递回客户端)。

注意:仅将域添加为参考项目。

基础结构(类库)

这些类负责外部基础结构通信,如数据库存储、文件系统、外部系统/API/服务等。我们可以在这个项目文件夹下为外部插件或SDK添加更多类库。

从本质上讲,基础设施层在技术上是不需要的,因为您可以设计一个不与外界交互的应用程序,并且所有应用程序都拥有自己的业务逻辑,这肯定是常态的例外!

它是系统的最外层,应该不了解内层。

注意:添加了应用程序类作为参考。

注意UI应用程序从不依赖于基础结构层,但是在这种情况下,我们必须将基础结构层引用到UI项目中以注册服务依赖项注入。因此,UI项目不应使用依赖注入以外的基础结构层的任何代码。

应用程序层需要注入基础结构类,因此这必须来自Web API层(UI层不使用基础结构,只用于DI到应用程序层)。

API 的项目program.cs——配置基础结构DI

使用注入的基础结构类的应用程序服务:

在下图中,您可以看到项目之间的内部参考结构。API项目必须引用应用程序层,以便它可以调用各种业务逻辑服务(它引用基础结构仅用于DI目的)。

应用层——接口

干净架构方法的主要特征之一是将所有接口放在一个地方,即应用程序项目。这表明在为解决方案的其他部分生成单元测试时,只需要模拟这一层。所有你在一个地方模拟的东西都可以更容易地进行单元测试。

因此,下面我将为基础结构存储库类(在基础结构项目中)生成一个接口,然后将其移动到应用程序项目。

注意:默认情况下,它将在类中创建接口,我们将在创建后移动它。Infrastructure

DTO

尽管DTO本身就是实体,因此您可能会认为它们应该进入Domain项目,但任何项目中DTO的经验法则是,它们应该进入(最)使用它们的项目。对于与Web相关的解决方案,这将是API层——因为来自客户端的数据将是DTO,而进入客户端的数据将是映射实体(到DTO)。

但是,将DTO放在靠近使用位置的另一个有力论据是,如果它们进入Domain项目,即使新的API希望使用应用程序服务,它们也会使用相同的结构进行设置——从而使API\Client更加灵活,Domain不应该规定客户端将接收的数据格式, 这应该留给每个单独的API项目。

已启用Swagger(启动设置API

Swagger包添加到API项目后,您可以按如下方式配置项目:

更改您的program.cs类以考虑您的Swagger设置:

Polly重试策略

Polly是在Blazor UI 应用程序program.cs文件中配置的,下面我正在使用 appsettings.json 文件来选取各种设置(重试计数和基本URL)并将它们分配给每个API调用——下面我声明重试API调用最多5次,此外它会抖动重试,以免立即用调用使服务器不堪重负。

测试Polly

仅运行Blazor应用程序(不与API结合使用),然后从左侧菜单中再次调用获取相册数据选项——请注意,它将重试5次(5次来自我们的appset),然后放弃。

 

日志记录(服务器端)

NLog配置为您希望如何记录数据;下面我只是在API项目中设置它以将所有内容记录到日志文件中(使用项目根目录上的 nlog.file)。

在程序中配置NLog.cs

示例输出:

单元测试——MSTest\Faker\Bogus

下面,我正在使用模拟数据(使用Bogus包)配置单元测试,其中我伪造了从存储库调用返回的数据,因此我可以对应用程序项目中保存的业务逻辑\用例进行单元测试——您可以查看解决方案项目中的单元测试代码:

https://www.codeproject.com/Articles/5351235/Clean-Architecture-Incorporating-Repository-Patter

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值