用NetCore + ReactJS 实现一个前后端分离的网站 (1) 搭建后端项目框架
1. 前言
做了几年的.Net开发,技术虽然在慢慢地进步,但是对.Net的使用还停留在满足工作要求的层面上。
最开始并没有系统地学习过.Net,而是从阅读、修改前人的代码开始,遇到问题上网搜这样的模式一点点积累起来的知识。
后来者们遇到的问题,基本都能解答,但这依然是在我的舒适圈里,并没有涉及到我没接触过、或者不太熟悉的技术。
而这个过程从.NetFramework一直持续到.NetCore时期。
所以,当.NetCore的各种特性扑面而来的时候,只能就事论事地去研究,导致每样都懂一点,但不多,不成体系,心里因此也是惴惴不安,没有底气说可以熟练地使用.NetCore。
所以,特意开了博客,利用一个项目来集成尽可能多的特性,毕竟只有亲自动手去架构一个完整的项目,并且能够表述清楚,才算是掌握了这样技术。
好了,闲话少数,咱们进入正文。
2. 需求
我准备做一个合作写小说的网站,后端用.NetCore来实现API,前端用ReactJS来实现。
用户可以注册、登录、编写大纲、合作写作等等。
一来要先确定后端基础业务逻辑,二来我还没学过ReactJS(笑着哭),所以先做后端。
3. 技术方案
这里首先确定一个基本的技术方案,后期根据功能往里面添加新的模块。
序号 | 类型 | 值 |
---|---|---|
1 | 开发环境 | VS2022 |
2 | .Net版本 | 6 |
3 | 数据库 | SqlServer(开发用,生产环境可以适配其他数据库), CodeFirst |
4 | ORM | EFCore |
4. 项目框架
我们先创建一个标准的项目框架,如下图所示,有5个工程:API层、实体层、公共层、服务接口层、服务层。
先说下我在项目框架上的历程。
- 一开始接触.Net项目的时候,用的都是传统的三层架构。
- 数据层:在数据库中用存储过程实现增删改查,使用SqlHelper访问数据库,并将执行结果返回到方法中。
- 业务层: 将数据层中的业务组合成展示层需要的复杂逻辑。
- 展示层:调用业务层提供的方法实现页面交互。
实际使用中,业务层经常会被忽略掉,成为展示层和数据层之间的传声筒,因为业务逻辑都在存储过程中实现了。
- 后来用上MVC架构的时候,也只是把controller作为展示层直接调用业务层的方法。
- 再后来用上EFCore的时候,取消了存储过程的使用,大部分业务逻辑在代码中通过LINQ予以实现,数据库则单纯地作为一个数据存储和查询的地方。
一开始用的还是挺舒服的,直到后来遇到并发修改数据,以及多对一数据库同步的问题(这个以后再讨论)。 - 再后来又接触到控制反转、依赖注入的概念,老实说一开始挺抗拒的,可以直接调用,为啥要写那么多的接口。
后来嘛,真香~
接下来我们实际编写代码。
4.1. 创建实体
Novel.cs
namespace NovelTogether.Core.Model
{
public class Novel
{
public int ID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string SubType { get; set; }
public string Description { get; set; }
public int CreatedBy { get; set; }
public DateTime CreatedTime { get; set; }
public int? ModifiedBy { get; set; }
public DateTime? ModifiedTime { get; set; }
public bool IsDeleted { get; set; }
}
}
4.2. 创建服务接口
这里只做演示用,后面会抽到IBaseService中,然后让IXXXSerice去继承,而不用写重复的代码。
INovelService.cs
using NovelTogether.Core.Model;
namespace NovelTogether.Core.IService
{
public interface INovelService
{
Task<List<Novel>> SelectAsync();
}
}
4.3. 创建服务类
NovelService.cs
using NovelTogether.Core.IService;
using NovelTogether.Core.Model;
namespace NovelTogether.Core.Service
{
public class NovelService: INovelService
{
public async Task<List<Novel>> SelectAsync()
{
return await Task.FromResult(
new List<Novel>()
{
new Novel(){ ID = 1, Name = "三国演义", CreatedBy = 1, CreatedTime = DateTime.Now }
});
}
}
}
4.4. 创建API
这里简单地New了服务类,后面会用依赖注入来实现。
NovelController.cs
using Microsoft.AspNetCore.Mvc;
using NovelTogether.Core.IService;
using NovelTogether.Core.Model;
using NovelTogether.Core.Service;
namespace NovelTogether.Core.API.Controllers
{
[ApiController]
[Route("[controller]")]
public class NovelController : Controller
{
[HttpGet]
public async Task<List<Novel>> Get()
{
INovelService service = new NovelService();
return await service.SelectAsync();
}
}
}
4.5. 测试API
按F5开始执行程序,在Swagger中执行这个方法,得到了在服务层中预设的数据。
到这里,一个简单的demo就做完了。目前这还不是一个完整的框架,下一期引入依赖注入来实现控制反转,避免大量的New关键字。