图书目录

目  录

第1部分  创建领域模型

第1章  领域驱动设计的概念 2

1.1  软件的复杂性 2

1.2  领域驱动设计简介 3

1.2.1  限界上下文 3

1.2.2  战略设计 4

1.2.3  领域模型 5

1.2.4  通用语言 5

1.3  领域驱动设计使用中的难点 5

1.3.1  对软件复杂性理解的偏差 6

1.3.2  术语的理解 6

1.3.3  技术框架问题 7

1.3.4  英语障碍 8

1.4  学习和使用领域驱动设计的一些体会 9

1.4.1  理解领域驱动设计的精髓 9

1.4.2  使用“战略设计”规划项目 9

1.4.3  在开发过程中使用“战术设计” 10

1.4.4  在学习中尽量尝试各种技术,在实践中保持简洁 11

1.4.5  实事求是,避免将理论当作教条 11

1.5  本书概况 11

1.5.1  本书的目标和结构 11

1.5.2  为什么选择.Net 12

1.5.3  本书选择的示例 12

1.5.4  本书使用的开发环境 12

1.5.5  本书中的数据和代码 13

1.6  本章小结 13

第2章  从零开始构建诗词游戏 14

2.1  需求概述 14

2.2  领域、子域与限界上下文 15

2.3  限界上下文的初步确定 16

2.3.1  用户认证上下文 18

2.3.2  诗词游戏上下文 19

2.3.3  诗词服务上下文 19

2.3.4  游戏管理上下文 19

2.4  限界上下文映射 19

2.4.1  各行其道 20

2.4.2  已发布语言 20

2.4.3  开放主机服务 20

2.4.4  客户-供应商 21

2.4.5  跟随者 21

2.4.6  防腐层 21

2.4.7  合作方式 21

2.4.8  共享内核 22

2.5  诗词游戏上下文的通用语言 22

2.6  创建第一个版本 23

2.7  本章小结 27

第3章  理解领域模型 28

3.1  领域模型概述 28

3.2  实体 28

3.2.1  实体的基本概念 29

3.2.2  从业务概念中发现实体 31

3.2.3  实体中数据的封装 33

3.2.4  实体中的方法 35

3.2.5  为什么要避免“贫血”模型 37

3.3  值对象 38

3.3.1  值对象的概念 38

3.3.2  值对象的实现 39

3.3.3  在模型中使用值对象的好处 41

3.4  聚合和聚合根 42

3.5  存储库 43

3.5.1  存储库的概念 43

3.5.2  存储库接口示例 44

3.5.3  是否可以使用EF Core等技术代替存储库 46

3.5.4  构建测试用的存储库实现 46

3.6  领域事件 48

3.6.1  为什么需要领域事件 48

3.6.2  领域事件的概念 49

3.6.3  在项目中增加领域事件 49

3.7  重构项目框架 57

3.8  完善诗词服务 58

3.9  本章小结 62

第4章  领域服务与应用服务 63

4.1  第一个领域服务 63

4.2  对游戏进行优化 65

4.2.1  问题分析 65

4.2.2  设计模式的使用 66

4.2.3  解决方案 67

4.3  领域服务的引入 69

4.4  应用服务 72

4.4.1  创建游戏 73

4.4.2  游戏过程 77

4.5  领域服务与应用服务的区别 83

4.6  避免滥用领域服务 84

4.7  本章小结 84

第5章  领域模型的验证与演化 85

5.1  领域模型构建过程回顾 85

5.2  领域模型设计需要注意的几个问题 86

5.2.1  学习领域知识,充分沟通 86

5.2.2  分析模式与设计模式的使用 86

5.2.3  遵守软件设计的一般规律 86

5.2.4  避免过度抽象 87

5.3  使用测试框架创建验证领域模型的测试用例 87

5.3.1  创建测试项目 87

5.3.2  模拟对象的使用 91

5.3.3  对异常的测试 92

5.4  使用行为驱动设计工具SpecFlow验证领域模型 93

5.4.1  行为驱动设计与领域驱动设计 94

5.4.2  使用SpecFlow验证领域模型 94

5.5  创建控制台应用验证领域模型 98

5.6  领域模型发布 98

5.7  领域模型的演化与持续集成 102

5.8  本章小结 103

第6章  创建基于控制台的人机游戏 104

6.1  已完成工作回顾 104

6.2  人机游戏说明 105

6.3  系统结构 105

6.4  创建应用层 106

6.5  模拟机器人作答 110

6.6  编写客户端 114

6.7  需要解决的问题 118

6.7.1  对象创建方式过于复杂 118

6.7.2  简单工厂不能满足扩展需求 119

6.7.3  应用层没有隔离领域层 119

6.7.4  其他需要解决的问题 120

6.8  本章小结 121

第2部分  DDD .Net工具箱

第7章  DDD .Net相关技术概述 124

7.1  .Net简介 124

7.1.1  .Net的发展简史 124

7.1.2  .Net的版本 125

7.1.3  .Net的跨平台支持 125

7.2  .Net功能 125

7.2.1  异步编程模式 125

7.2.2  特性 126

7.2.3  反射 128

7.2.4  委托 129

7.2.5  事件 131

7.2.6  泛型 132

7.2.7  LINQ 133

7.3  与领域驱动设计实现相关的技术框架 134

7.3.1  依赖注入框架 134

7.3.2  ORM框架 134

7.3.3  对象映射框架 135

7.3.4  实时通信框架 135

7.3.5  进程内消息框架 135

7.4  本章小结 136

第8章  依赖倒置原则、控制反转与DDD架构 137

8.1  依赖倒置原则 137

8.1.1  概述 137

8.1.2  在设计中引入依赖倒置原则 138

8.1.3  设计期依赖与运行期依赖 140

8.1.4  依赖倒置实例 143

8.2  控制反转 144

8.2.1  问题的提出 144

8.2.2  理解控制反转 146

8.2.3  IoC容器 146

8.3  架构结构的转变 146

8.4  本章小结 148

第9章  工厂与依赖注入容器 149

9.1  工厂 149

9.1.1  工厂的概念 149

9.1.2  工厂设计模式 150

9.2  依赖注入容器 151

9.2.1  问题的提出 152

9.2.2  理解依赖注入 152

9.3  .Net内置的依赖注入容器 153

9.3.1  基本使用方法 153

9.3.2  服务对象的生命周期 153

9.3.3  服务的注册方法 154

9.3.4  多个构造函数的情况 156

9.4  依赖注入容器的使用 156

9.4.1  在控制台应用中使用依赖注入 156

9.4.2  改造简单工厂 157

9.4.3  可插拔组件架构实现 159

9.5  使用第三方DI容器满足高级需求 159

9.5.1  基本使用方法 160

9.5.2  属性注入 161

9.5.3  使用基于名称的注入改造工厂 161

9.5.4  程序集注册 163

9.6  本章小结 163

第10章  基于关系数据库的存储库实现 164

10.1  EF Core的基本功能 164

10.2  使用EF Core实现存储库 167

10.2.1  创建PlayerRepository 167

10.2.2  创建GameRepository 170

10.3  EF Core的深入应用 173

10.3.1  多数据库类型支持 173

10.3.2  生产环境的数据库部署 178

10.3.3  数据库生成标识 182

10.3.4  Data Annotations vs Flunt API 183

10.4  在控制台应用中使用新的存储库 184

10.5  使用其他数据库访问框架实现存储库 185

10.5.1  存储库的持久层框架需要满足的条件 185

10.5.2  Dapper 186

10.5.3  FreeSql 187

10.6  本章小结 187

第11章  存储库与NoSQL数据库 188

11.1  NoSQL数据库概述 188

11.1.1  键值对存储数据库 188

11.1.2  列存储数据库 188

11.1.3  文档型数据库 189

11.1.4  Graph数据库 189

11.1.5  实时数据库 189

11.2  文档数据库MongoDB概述 189

11.2.1  MongoDB介绍 189

11.2.2  MongoDB的安装 190

11.2.3  MongoDB的管理 190

11.2.4  MongoDB的基本概念 191

11.2.5  MongoDB的基本数据类型 191

11.3  创建面向MongoDB的存储库 192

11.3.1  使用MongoDB.Driver操作MongoDB 192

11.3.2  创建存储库 194

11.3.3  使用依赖注入传入MongoDB数据库访问对象 200

11.3.4  注意事项 201

11.4  聚合根在MongoDB中存储与在关系数据库中存储的比较 202

11.5  本章小结 202

第12章  认证 203

12.1  基本概念 203

12.2  Asp.Net Core Identity 204

12.2.1  简介 205

12.2.2  创建使用Identity的Web应用 205

12.2.3  集成Identity与诗词游戏 207

12.2.4  Identity的配置 210

12.2.5  个性化Identity页面 212

12.2.6  Identity的使用场景 214

12.3  基于OpenId Connect的认证服务 214

12.3.1  OAuth 2.0、OpenId和OpenId Connect介绍 214

12.3.2  使用Identity Server 4创建用户管理和认证功能 215

12.3.3  使用Identity Server 4保护Web 应用 217

12.3.4  集成Identity Server 4与诗词游戏 222

12.4  在实际项目中使用认证服务 222

12.4.1  单点登录 222

12.4.2  前后端分离的应用 223

12.4.3  分布式应用 224

12.5  本章小结 225

第13章  领域事件实现 226

13.1  领域事件的工作过程 226

13.2  观察者模式、中介者模式与订阅/发布模式 229

13.2.1  观察者模式 230

13.2.2  中介者模式 231

13.2.3  订阅/发布模式 232

13.3  使用MediatR实现领域事件发布 233

13.3.1  引入MediatR 233

13.3.2  将领域事件封装为MediatR消息 233

13.3.3  事件总线实现 234

13.3.4  事件的接收和处理实现 237

13.3.5  事件发布 239

13.4  外部事件发布与消息中间件 240

13.5  本章小结 246

第14章  应用层开发 247

14.1  应用层概述 247

14.1.1  应用服务 247

14.1.2  数据传输对象 247

14.1.3  工作单元 248

14.2  应用层创建示例 249

14.2.1  控制台应用与Web应用的不同 249

14.2.2  创建新的应用层接口 252

14.2.3  应用层实现 255

14.3  创建应用层的Web API 257

14.4  引入工作单元 263

14.4.1  工作单元的定义 263

14.4.2  工作单元的实现 263

14.4.3  工作单元的使用 272

14.5  本章小结 272

第15章  使用Web API和gRPC实现限界上下文集成 273

15.1  直接访问诗词服务数据库 273

15.2  使用Web API实现上下文集成 277

15.2.1  编写诗词服务的Web API 277

15.2.2  编写访问Web API的PoemService接口 280

15.2.3  测试Web API和客户端 281

15.2.4  是否使用RESTful形式的Web API 283

15.3  使用gRPC实现限界上下文集成 284

15.3.1  RPC与gRPC 284

15.3.2  gRPC对.Net的支持 284

15.3.3  编写gRPC PoemService服务 287

15.3.4  编写gRPC PoemService客户端 292

15.3.5  编写验证控制台程序 294

15.3.6  编写gRPC应用的其他注意事项 296

15.3.7  gRPC重试策略的配置 297

15.4  本章小结 298

第16章  使用消息实现限界上下文集成 299

16.1  限界上下文集成方案 299

16.1.1  消息中间件的使用 299

16.1.2  创建对外发布消息的接口 300

16.1.3  创建消息接收接口 302

16.1.4  消息接收程序 302

16.2  使用RabbitMQ实现限界上下文集成 304

16.2.1  编写消息接收端 304

16.2.2  消息发布 307

16.2.3  在控制台项目中使用配置文件 309

16.2.4  编写接收端插件 310

16.2.5  RabbitMQ消息类型简介 312

16.3  使用Kafka实现限界上下文集成 314

16.3.1  Kafka消息发送端的编写 314

16.3.2  Kafka消息接收端的编写 315

16.4  本章小结 318

第3部分  构建以领域模型为核心的应用

第17章  “战略设计”与架构选择 320

17.1  从业务出发规划项目架构 320

17.1.1  问题的提出 320

17.1.2  战略设计的作用 321

17.1.3  限界上下文之间的架构 322

17.2  示例项目的“战略设计” 323

17.2.1  限界上下文的划分 323

17.2.2  诗词游戏上下文 323

17.2.3  用户认证上下文 324

17.2.4  诗词服务上下文 324

17.2.5  游戏管理上下文 324

17.3  与DDD相关的架构类型 324

17.3.1  分层架构 324

17.3.2  六边形架构 324

17.3.3  洋葱圈架构 325

17.3.4  整洁架构 326

17.4  使用架构描述、设计应用系统 327

17.4.1  总体架构 327

17.4.2  存储库 330

17.4.3  领域服务的扩展 331

17.4.4  领域事件发布 332

17.4.5  与其他限界上下文的集成 333

17.4.6  使用消息实现与其他限界上下文的集成 335

17.5  架构模型的总结 336

17.6  本章小结 337

第18章  构建Web单体应用 338

18.1  单体应用概述 338

18.2  需求细化 338

18.3  系统架构 340

18.4  应用层 341

18.5  使用SignalR创建实时服务 344

18.5.1  SignalR介绍 344

18.5.2  创建SignalR服务端 345

18.5.3  创建SignalR的JavaScript客户端 347

18.5.4  创建Razor页面 350

18.6  装配依赖注入服务 353

18.7  运行效果和待解决的问题 354

18.8  本章小结 357

第19章  构建游戏服务 358

19.1  需求分析 358

19.2  项目搭建 360

19.3  编写服务层 360

19.4  SignalR Hub的实现 365

19.5  定时器的引入 371

19.6  安全认证 374

19.7  使用依赖注入服务进行装配 377

19.8  本章小结 378

第20章  单页面客户端 379

20.1  需求概述 379

20.2  技术方案 380

20.2.1  单页面客户端在架构中的位置 380

20.2.2  关键技术 381

20.3  前端项目构建 383

20.3.1  创建项目 383

20.3.2  使用oidc-client进行认证 386

20.3.3  访问游戏服务的SignalR Hub 388

20.3.4  编写客户端逻辑 392

20.4  交互设计 393

20.4.1  交互设计原则 393

20.4.2  诗词游戏的交互设计 394

20.4.3  运行效果 395

20.5  本章小结 398

第21章  使用.Net构建多种类型客户端 399

21.1  概述 399

21.2  认证 400

21.2.1  IdentityModel.OidcClient介绍 400

21.2.2  控制台应用的认证功能实现 401

21.2.3  WinForm应用认证功能实现 403

21.2.4  Android移动应用的认证功能实现 408

21.3  Web API的访问 412

21.3.1  使用HttpClient访问Web API 412

21.3.2  控制台应用的Web API访问 412

21.3.3  WinForm的Web API访问 413

21.3.4  Android应用的Web API访问 414

21.4  SignalR的访问 415

21.4.1  SignalR的C#客户端 415

21.4.2  控制台应用访问SignalR Hub 416

21.4.3  WinForm访问SignalR Hub 417

21.4.4  Android App访问SignalR 418

21.5  客户端交互模式与应用服务 420

21.6  本章小结 420

第22章  微服务 421

22.1  微服务简介 421

22.1.1  基本概念 421

22.1.2  微服务的优点 422

22.1.3  使用微服务的代价 422

22.1.4  一个没有很好设计的微服务示例 423

22.2  微服务相关的技术 423

22.2.1  容器 424

22.2.2  微服务编排 424

22.2.3  微服务相关的其他技术 424

22.3  使用微服务架构的诗词游戏 426

22.3.1  需求分析 426

22.3.2  后端实现 427

22.3.3  前端实现 431

22.3.4  使用Docker Compose创建容器 433

22.4  容器化部署 437

22.4.1  单页面前端的容器化部署 437

22.4.2  Asp.Net Core项目的容器化部署 437

22.4.3  基础设施的容器化部署 439

22.4.4  诗词游戏的容器化部署 440

22.4.5  使用反向代理服务器整合应用的各个部分 441

22.5  持续集成 443

22.5.1  持续集成简介 443

22.5.2  手工集成过程 443

22.5.3  使用Jenkins完成自动集成 445

22.6  本章小结 447

第23章  诗词服务数据维护——非DDD技术的限界上下文 448

23.1  数据驱动开发简介 448

23.2  诗词服务数据维护的开发 449

23.3  数据驱动开发与DDD的比较 453

23.4  本章小结 455

第24章  游戏管理上下文的实现与CQS模式 456

24.1  游戏管理部分的设计 456

24.2  游戏管理部分的领域模型 457

24.2.1  领域模型定义 457

24.2.2  存储库的实现 459

24.3  查询部分设计 462

24.3.1  查询接口 462

24.3.2  查询实现 468

24.4  游戏管理服务设计 469

24.5  游戏管理客户端设计 472

24.6  CQRS简介 473

24.7  本章小结 474

第25章  使用成熟的DDD技术框架 475

25.1  ABP和ABP vNext 475

25.1.1  ASP.NET Boilerplate(ABP) 475

25.1.2  ABP vNext 476

25.2  使用ABP vNext开发项目 476

25.3  使用辅助工具进行开发 478

25.4  使用技术框架开发的优势和代价 479

25.5  如何使用技术框架 480

25.6  本章小结 480

第26章  系统提升与持续改进 481

26.1  模型对需求变化的适应性 481

26.1.1  游戏类型的增加 481

26.1.2  增加不同数据源的游戏类型 483

26.1.3  限制数据范围 484

26.2  软件升级时模型的修改 484

26.2.1  挖掘现有模型的潜力 484

26.2.2  引入新的领域概念 486

26.3  使用语音输入对系统的影响 488

26.4  架构的持续改进 488

26.5  本章小结 491

后记 492

附录A  本书使用的开发工具、开发环境介绍 494

A.1  Docker 494

A.2  Git 494

A.3  NuGet 495

A.4  xUnit 495

A.5  SpecFlow 495

A.6  MongoDB 495

A.7  MS SQL Server 496

A.8  RabbitMQ 496

A.9  Kafka 497

A.10  Jenkins 500

A.11  Identity Server 4 admin 500

附录B  参考文献 509

附录C  本书代码说明 511