26 | 工程结构概览:定义应用分层及依赖关系

从这一节开始进入微服务实战部分

这一节主要讲解工程的结构和应用的分层

在应用的分层这里定义了四个层次:

1、领域模型层

2、基础设施层

3、应用层

4、共享层

可以通过代码来看一下

共享层一共建立三个工程:

1、GeekTime.Core:主要承载基础的简单的类型,比如说异常或者一些帮助类

2、GeekTime.Domain.Abstractions:抽象层,领域的抽象是指在领域模型可以定义一些基类或者接口,领域事件接口,领域事件处理接口,还有 Entity 的接口和 Entity 的基类

3、GeekTime.Infrastructure.Core:基础设施的核心层,是指对仓储,还有 EFContext 定义一些共享代码

这些包实际上在不同的项目里面都可以共享,所以建议的做法是把这些代码都通过私有的 NuGet 的仓库来存储,然后其他的工程可以使用 NuGet 包来直接引用即可

领域模型层就是定义领域模型的地方,这里面会有不同的聚合,还有领域事件,不同的聚合下面就是领域模型

基础设施层是仓储层和一些共享代码的实现,这里只定义了仓储层的实现,包括 EF 的 DomainContext,还有 Order 的仓储层,User 的仓储层,还定义了领域模型与数据库之间的映射关系,就是在 EntityConfigurations 这目录下面去定义

应用层分两个,一个工程是 API 层,是用来承载 Web API 或者 Web 应用的,另外一个是后台任务,这个就是用来执行一些特殊的 Job,作为 Job 的宿主运行的,它可以是一个控制台的应用程序

在 Web 层,Web API 层,也分了几个关键目录 Application,Controllers,Extensions,Infrastructure

基础设施层会放一些身份认证缓存之类的与基础设施交互相关的一些代码

扩展层主要是将服务注册进容器的代码和中间件配置的代码,也就是两扩展方法,一个是对 ServiceCollection 的扩展,一个是对 ApplicationBuilder 的扩展

控制器层主要用来定义 Web API,这一层就是定义前后端交互的接口

应用层使用了 CQRS 的设计模式,就是命令与查询职责分离,把命令放在一个目录,把查询放在一个目录,同样的这里还有两个事件处理的目录,一个是领域模型,领域事件的处理,一个是集成事件的处理

再看一下各层之间的依赖关系

Shared 层实际上是不依赖任何层次的,它存储了共享的代码,被各个工程共享

GeekTime.Core,GeekTime.Domain.Abstractions 是不依赖任何工程的,而 GeekTime.Infrastructure.Core 依赖了 GeekTime.Domain.Abstractions,实现了仓储,比如说仓储会依赖 IAggregateRoot 接口

public interface IRepository<TEntity> where TEntity : Entity, IAggregateRoot

领域模型需要继承模型的基类,并且实现一个聚合根的接口,表示它是一个聚合根

public class Order : Entity<long>, IAggregateRoot

领域事件需要实现一个领域事件的接口

public class OrderCreatedDomainEvent : IDomainEvent

基础设施层是一个独立的程序集,实现了仓储的部分,定义了一个 Order 的仓储

public interface IOrderRepository : IRepository<Order, long>

还定义了 Order 仓储的实现

public class OrderRepository : Repository<Order, long, DomainContext>, IOrderRepository
{
public OrderRepository(DomainContext context) : base(context)
{
}
}

这里可以看到仓储实际上依赖了基础设施层共享代码里面的仓储的定义 IRepository,这样就可以复用仓储层的代码,这样定义 OrderRepository 就会比较简单,可以复用 Repository 的一些实现

public abstract class Repository<TEntity, TKey, TDbContext> : Repository<TEntity, TDbContext>, IRepository<TEntity, TKey> where TEntity : Entity<TKey>, IAggregateRoot where TDbContext : EFContext
{
public Repository(TDbContext context) : base(context)
{
} public virtual bool Delete(TKey id)
{
var entity = DbContext.Find<TEntity>(id);
if (entity == null)
{
return false;
}
DbContext.Remove(entity);
return true;
} public virtual async Task<bool> DeleteAsync(TKey id, CancellationToken cancellationToken = default)
{
var entity = await DbContext.FindAsync<TEntity>(id, cancellationToken);
if (entity == null)
{
return false;
}
DbContext.Remove(entity);
return true;
} public virtual TEntity Get(TKey id)
{
return DbContext.Find<TEntity>(id);
} public virtual async Task<TEntity> GetAsync(TKey id, CancellationToken cancellationToken = default)
{
return await DbContext.FindAsync<TEntity>(id, cancellationToken);
}
}

已经实现了一些基本的方法,增删改查的方法

数据库访问的实现,继承了自己定义的 EFContext,EFContext 作为共享代码在各个工程里面复用

public class DomainContext : EFContext

另外一个比较特殊的是事务处理的对象,这个对象是用来管理整个应用程序的请求上下文中的事务,这样就可以避免手动地去处理事务,简化代码

public class DomainContextTransactionBehavior<TRequest, TResponse> : TransactionBehavior<DomainContext, TRequest, TResponse>
{
public DomainContextTransactionBehavior(DomainContext dbContext, ICapPublisher capBus, ILogger<DomainContextTransactionBehavior<TRequest, TResponse>> logger) : base(dbContext, capBus, logger)
{
}
}

应用层依赖了基础设施层,基础设施层又依赖了领域层

应用层实际上是把各层组装在一起的这一层,它是应用程序的一个宿主,协调各层之间的关系,以及组装代码都是在这里实现的

总结一下

领域模型层专注于业务的设计,它不依赖于其他各层,它是相对独立的

基础设施的仓储层仅仅负责领域模型的存取,它不负责任何的业务逻辑代码的承载

推荐使用 CQRS 的模式来设计应用程序,使应用程序的代码结构更加的合理,在团队和项目膨胀的情况下,工程的可维护性不至于急剧的下降

Web API 是面向前端交互的接口,避免依赖领域模型

共享代码建议设计为共享包,使用私有的 NuGet 仓库来分发和管理

GitHub源码链接:

https://github.com/witskeeper/geektime

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

.NET Core开发实战(第26课:工程结构概览:定义应用分层及依赖关系)--学习笔记的更多相关文章

  1. 2月送书福利:ASP.NET Core开发实战

    大家都知道我有一个公众号“恰童鞋骚年”,在公众号2020年第一天发布的推文<2020年,请让我重新介绍我自己>中,我曾说到我会在2020年中每个月为所有关注“恰童鞋骚年”公众号的童鞋们送一 ...

  2. [ASP.NET Core开发实战]开篇词

    前言 本系列课程文章主要是学习官方文档,再输出自己学习心得,希望对你有所帮助. 课程大纲 本系列课程主要分为三个部分:基础篇.实战篇和部署篇. 希望通过本系列课程,能让大家初步掌握使用ASP.NET ...

  3. [ASP.NET Core开发实战]基础篇02 依赖注入

    ASP.NET Core的底层机制之一是依赖注入(DI)设计模式,因此要好好掌握依赖注入的用法. 什么是依赖注入 我们看一下下面的例子: public class MyDependency { pub ...

  4. .NET Core开发实战(第11课:文件配置提供程序)--学习笔记

    11 | 文件配置提供程序:自由选择配置的格式 文件配置提供程序 Microsoft.Extensions.Configuration.Ini Microsoft.Extensions.Configu ...

  5. 2、SpringBoot接口Http协议开发实战8节课(1-6)

    1.SpringBoot2.xHTTP请求配置讲解 简介:SpringBoot2.xHTTP请求注解讲解和简化注解配置技巧 1.@RestController and @RequestMapping是 ...

  6. [ASP.NET Core开发实战]基础篇03 中间件

    什么是中间件 中间件是一种装配到应用管道,以处理请求和响应的组件.每个中间件: 选择是否将请求传递到管道中的下一个中间件. 可在管道中的下一个中间件前后执行. ASP.NET Core请求管道包含一系 ...

  7. [ASP.NET Core开发实战]基础篇01 Startup

    Startup,顾名思义,就是启动类,用于配置ASP.NET Core应用的服务和请求管道. Startup有两个主要作用: 通过ConfigureServices方法配置应用的服务.服务是一个提供应 ...

  8. 2、SpringBoot接口Http协议开发实战8节课(7-8)

    7.SpringBoot2.x文件上传实战 简介:讲解HTML页面文件上传和后端处理实战 1.讲解springboot文件上传 MultipartFile file,源自SpringMVC 1)静态页 ...

  9. [ASP.NET Core开发实战]基础篇06 配置

    配置,是应用程序很重要的组成部分,常常用于提供信息,像第三方应用登录钥匙.上传格式与大小限制等等. ASP.NET Core提供一系列配置提供程序读取配置文件或配置项信息. ASP.NET Core项 ...

  10. [ASP.NET Core开发实战]基础篇05 服务器

    什么是服务器 服务器指ASP.NET Core应用运行在操作系统上的载体,也叫Web服务器. Web服务器实现侦听HTTP请求,并以构建HttpContext的对象发送给ASP.NET Core应用. ...

随机推荐

  1. Element 动态表头渲染表格

    element 中的table表头动态渲染 https://blog.csdn.net/heixiuheixiu666/article/details/104705024/ Element 动态表头渲 ...

  2. mongodb导入本地json文件

  3. java基础(16)--super与this

    一.this简介 1.this.  this() 2.静态方法无法使用 3.不省略的情况:区分局部变量与实例变量,比如set方法中用到   二.super简介 1.只能出现在实例方法或构造方法中 2. ...

  4. 洛谷 P9683 A Certain Forbidden Index 题解

    题目链接:\(\color{Purple}\texttt{P9683 A Certain Forbidden Index}\). 填坑.提供一个相对好写的做法. 考虑把一堆不交的区间绑在一起问(即先询 ...

  5. ORACLE Enterprise Manager Database Express(OEM-express)(遇到localhost拒绝访问情况)配置端口和启动方法

    1.问题 之前一直进不去ORACLE Enterprise Manager Database Express,显示的是localhost拒绝了访问,经过查阅知道是没有配置相应端口. 2.解决方法 转载 ...

  6. 【转】国产飞腾D2000:基于A72?

    https://zhuanlan.zhihu.com/p/612054128 China's Phytium D2000: Building on A72? 国产飞腾D2000:基于A72? PS:麒 ...

  7. 不同数据库创建用户,数据库的SQL语句整理

    不同数据库创建用户,数据库的SQL语句整理 MySQL mysql -uroot -p # 输入密码登录数据库 CREATE DATABASE IF NOT EXISTS xxxdata_somein ...

  8. [转帖]Kafka故障之磁盘打满

    https://www.jianshu.com/p/095e820361ae 问:磁盘打满扩容后能正常重启吗?答:不一定 要看文件格式是否损坏(log.index等).如果损坏会报错:index fi ...

  9. [转帖]实战瓶颈定位-我的MySQL为什么压不上去

    https://plantegg.github.io/2023/06/20/%E5%AE%9E%E6%88%98%E7%93%B6%E9%A2%88%E5%AE%9A%E4%BD%8D-%E6%88% ...

  10. [转帖]jmeter 响应时间rt很小,但是tps也很小&jmeter,脚本处理,千万不要用js

    一.背景: 在压测的时候,查看jmeter聚合报告,发现rt很小,但是tps也很小. 讲道理来说,响应时间越小,tps应该越大. 一共压测10分钟,发现jmeter请求的样本数量非常小,才8500个请 ...