赞
踩
目录
本文档详细介绍了如何将存储库模式合并到干净的体系结构模式中。它涉及现有MVC模式(日志记录、单元测试、DI、EF Core等)中的许多常见方面。
产品架构文档(PAD)提供了有关如何将数据库优先方法集成到干净架构方法中的全面架构概述——涉及哪些组件以及它们如何相互关联。
此PAD的范围是传达使用存储库模式生成干净架构模式所需的概念。
使用此链接 https://github.com/Bert0Neill/CleanArchitectureDemo.git 克隆代码存储库。
从此处下载并安装Visual Studio的 EF Core Power Tools 扩展——EF Core Power Tools - Visual Studio Marketplace
为了使解决方案尽可能逼真,我使用了以下包和组件,这些包和组件当前将用于现有体系结构模式——这些包和组件已合并到使用它们的解决方案项目中。
清洁架构模式的概念已经存在了十多年,最初由罗伯特·马丁(更广为人知的名字是鲍勃叔叔)构思。鲍勃叔叔的关键词是可以互换的。在下图中,蓝色圆圈上的所有内容都是可以互换的,例如,UI可以从Angular换成React,或者数据库可以从Oracle迁移到MySQL,底层中的任何内容都不需要更改。
将所有接口(基础结构和应用程序)放在一个项目中的概念将使单元测试和模拟变得更加容易。
但清洁架构背后的主要理由是MVC不扩展或允许层的相同松散耦合。在清洁体系结构中,依赖项仅面向内部(这满足来自SOLID主体的DI)。在MVC中,模型视图充当UI和控制器层合二为一,这可能会变得非常大且难以测试(因为紧密耦合)。MVC已经为软件行业服务了20多年,但该行业希望在未来20年内采用一种新的更精简的架构模式——一种可扩展、可互换\解耦的架构模式。
基础设施处理“数据库”、“外部 API 调用”、“缓存”等。基本上,基础设施处理所有外部资源。基础结构取决于应用程序内部的“接口”。由于依赖关系反转,我们的应用程序将是松散耦合的,这使得测试变得容易。
UI应用程序使用“应用程序核心”来生成结果。在实时场景中,UI应用程序从不依赖于基础结构层,但是我们必须在注册服务依赖注入的情况下将基础结构层引用到UI项目中。因此,UI项目不应使用依赖注入以外的基础结构层的任何代码。
解决方案被拆分为解决方案文件夹,在每个文件夹中,都有一个项目(根据大小或复杂性,每层可以有多个项目,因此将一个层拆分为多个项目可能更有意义,维护明智):
下图显示了最终的UI屏幕(即从客户端Web应用程序到接口控制器的调用),而API控制器又调用应用程序服务(用例\业务逻辑),后者调用相应的基础结构类来执行外部任务。
数据库实体将保存在域项目本身中,右键单击域项目并从上下文菜单中选择“EF Core Power Tools”,然后选择“反向工程”。
然后,系统将提示您选择要对数据库模型进行反向工程的数据库。
接下来,您可以选择相应的数据库表来为其生成实体:
确保仅从“要生成的内容”下拉列表中选择“实体类型”,因为我们只希望创建实体,而不是Domain项目中的DBContext。输入创建实体的路径,右键单击Domain项目时,命名空间应该是正确的。
右键单击“基础结构”项目,然后再次选择“EF Core Power Tool”,对“(进入Application项目)进行反向工程” DBContext。
确保从下拉列表中选择“仅DbContext”,并输入要生成 DBContext类的路径:
然后,这将为相应项目中的实体和DBContext生成以下结构:
连接字符串放置在 API项目的Programs类中,因为我们正在使用该Application项目,而该项目又需要注入将使用DBContext。
将对DBContext(MusicContext来自基础结构项目)的引用添加到 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本身就是实体,因此您可能会认为它们应该进入Domain项目,但任何项目中DTO的经验法则是,它们应该进入(最)使用它们的项目。对于与Web相关的解决方案,这将是API层——因为来自客户端的数据将是DTO,而进入客户端的数据将是映射实体(到DTO)。
但是,将DTO放在靠近使用位置的另一个有力论据是,如果它们进入Domain项目,即使新的API希望使用应用程序服务,它们也会使用相同的结构进行设置——从而使API\Client更加灵活,Domain不应该规定客户端将接收的数据格式, 这应该留给每个单独的API项目。
将Swagger包添加到API项目后,您可以按如下方式配置项目:
更改您的program.cs类以考虑您的Swagger设置:
Polly是在Blazor UI 应用程序program.cs文件中配置的,下面我正在使用 appsettings.json 文件来选取各种设置(重试计数和基本URL)并将它们分配给每个API调用——下面我声明重试API调用最多5次,此外它会抖动重试,以免立即用调用使服务器不堪重负。
仅运行Blazor应用程序(不与API结合使用),然后从左侧菜单中再次调用“获取相册数据”选项——请注意,它将重试5次(5次来自我们的appset),然后放弃。
将NLog配置为您希望如何记录数据;下面我只是在API项目中设置它以将所有内容记录到日志文件中(使用项目根目录上的 nlog.file)。
在程序中配置NLog.cs:
示例输出:
下面,我正在使用模拟数据(使用Bogus包)配置单元测试,其中我伪造了从存储库调用返回的数据,因此我可以对应用程序项目中保存的业务逻辑\用例进行单元测试——您可以查看解决方案项目中的单元测试代码:
https://www.codeproject.com/Articles/5351235/Clean-Architecture-Incorporating-Repository-Patter
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。