Ater.Web.template 是基于ASP.NET Core
和EntityFramework Core
技术栈的项目模板,提供了开箱即用的项目结构和基础功能,帮助开发者快速搭建一个现代化的Web应用程序。
本着以结果为导向,实用为目标,在架构设计上,我们主要追求通用、简洁和灵活三个原则,致力于为开发者提供高效且易用的开发体验,三个原则的具体含义:
Important
文档中最佳实践是一个技术表达用语,指经过实践之后推荐的措施,并不是说是最好的实践。每个人或团队都可以有自己的最佳实践。
为了达成这样的目标,我们将项目开发分成两个部分:框架层
与项目层
。
在框架层指的是经过大量项目的经验积累,总结出来的最佳实践和约定。这些约定符合通用、简捷、灵活
的原则,旨在帮助开发者快速上手和理解项目结构,并能够基于此,快速实现业务逻辑代码。
我们将通过提供以下程序集来实现框架层的功能:
由于框架层与项目和业务无关,它们可以被打包成类库,为此我们提供了打包后的Nuget包,包括:
实际使用中,你可以直接安装Ater.Web.Extension
,它包含了Ater.Common
和Ater.Web.Convention
。
项目层其实是为了与框架层区分,指与本项目相关的层级结构,主要包括:
这是一个通用的流程,非常容易理解,对于各个行业的流程,我们都可以抽象出这三个步骤:定义->实现->服务。
定义层,定义业务模型,决定了业务的数据模型和行为,是业务实现的基础和前提,通常包括:
实现层,主要是实现业务逻辑,通过拆解成不同的Module来实现。
在实际需要中,业务需求常常涉及多个领域或多个业务模块,我们可以按照业务模块进行拆分,框架默认提供CommonMod
共享模块,被其他模块引用。
典型结构如下:
在实际开发中,主要通过Manager
实现业务逻辑。框架提供了ManagerBase
实现类,该类主要提供了默认的数据访问的能力。
最常见的用法是继承ManagerBase<TEntity>
,其中TEntity
对应一个业务实体模型,用来对该实体进行操作,称之为EntityManager。
通常EntityManager之间不会直接通过依赖注入进行互相调用,避免产生循环依赖。
典型的代码如下:
public class UserManager(DataAccessContext<User> dataContext,ILogger<UserManager> logger) : ManagerBase<User>(dataContext, logger) { }
请注意,这里注入了DataAccessContext<>
,它是一个数据访问上下文,只是对CommandDbContext
和QueryDbContext
的简单封装。
默认的ManagerBase<TEntity>
使用CommandDbContext
和QueryDbContext
,分别用于数据的读和写操作。如果你需要指定数据库上下文,或者不需要数据访问的能力,可以继承使用不同参数的ManagerBase
,以实现自己的逻辑。
可以在Definition/Share
程序集中的Implement
目录下查看ManagerBase.cs
。
ManagerBase
提供了对数据访问的支持,如果你的业务逻辑不涉及到数据状态的变化,建议将其封装成一个Service
,而不是一个Manager
。
Tip
关于使用ManagerBase
提供数据访问能力的内容,详情请查看数据访问文档,包括如何使用工厂模式支持多租户的数据库上下文创建。
在实现层中,我们将业务逻辑拆分成多个模块,每个模块实现自己的Manager
,模块的划分有助于将业务逻辑进行拆分和解耦,有助于多人的协作开发。
其中CommonMod
是一个通用共享模块,其他各个模块都会引用它。
模块的命名约定以Mod
结尾。
Module具有一定的独立性,无论是在业务上还是代码上,一个Module通常包括:
你也可以在Module中实现Controller
,以便可以在多个服务中复用,这也是一种实践。
服务层是面向实际调用者的,通常我们通过Restful API
或Grpc
来提供接口的调用。不同的服务通常使用不同的镜像去部署。
对于接口服务,我们需要关注的是:
在该层级,模板默认提供了以下服务
Restful API
提供接口服务。IdentityServer
提供身份认证服务。EF Core
提供数据库迁移服务。模板默认提供Http.API
项目以实现Restful API
接口服务,该程序集通常会依赖以下项目:
Manager
和Module
的扩展方法。在Program.cs
中,你会看到AddManagers
和AddModules
,这两个方法是用来添加业务模块的服务,它们由源代码生成器自动生成,无法手动修改,可以按F12
查看生成的代码。
框架提供了RestControllerBase
基类,该类定义了路由,注入了语言本地化服务,以及实现了常见的返回方法。
此外,提供了ClientControllerBase
和AdminControllerBase
,分别用于客户端和管理端的控制器基类,它们拥有不同的路由、授权和OpenAPI的分组。通常我们自己编写的控制器要继承其中的一个。
Tip
可在Definition/Share
程序集的Implement
查看RestControllerBase.cs
的实现。
在现代化应用开发中,越来越多的应用使用微服务方式来开发,然后使用容器来部署和运行,这是现代化开发中的主流方式。
微软提供.NET Aspire
来解决微服务开发中的一些痛点。在V10
版本,我们将默认使用.NET Aspire
来作为本地开发的默认集成。
模板中关于Aspire
的内容,一个是AspireHost
项目,一个是Definition
目录下的ServiceDefaults
项目。