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项目。