前言
我可能有三年没怎么碰C#了,目前的工作是在全职搞前端,最近有时间抽空看了一下Asp.net Core,Core版本号都到了5.0了,也越来越好用了,下面将记录一下这几天以来使用Asp.Net Core WebApi+Dapper+Mysql+Redis+Docker的一次开发过程。
项目结构
最终项目结构如下,CodeUin.Dapper数据访问层,CodeUin.WebApi应用层,其中涉及到具体业务逻辑的我将直接写在Controllers中,不再做过多分层。CodeUin.Helpers我将存放一些项目的通用帮助类,如果是只涉及到当前层的帮助类将直接在所在层级种的Helpers文件夹中存储即可。
安装环境
MySQL
1 | cmd复制代码# 下载镜像 |
如果正在使用的客户端工具连接MySQL提示1251,这是因为客户端不支持新的加密方式造成的,解决办法如下。
1 | shell复制代码# 查看当前运行的容器 |
最后,使用MySQL客户端工具进行连接测试,我使用的工具是Navicat Premium。
Redis
1 | shell复制代码# 下载镜像 |
使用Redis客户端工具进行连接测试,我使用的工具是Another Redis DeskTop Manager。
.NET 环境
服务器我使用的是CentOS 8,使用的NET SDK版本5.0,下面将记录我是如何在CentOS 8中安装.NET SDK和.NET运行时的。
1 | shell复制代码# 安装SDK |
检查是否安装成功,使用dotnet --info
命令查看安装信息
创建项目
下面将实现一个用户的登录注册,和获取用户信息的小功能。
数据服务层
该层设计参考了 玉龙雪山 的架构,我也比较喜欢这种结构,一看结构就知道是要做什么的,简单清晰。
首先,新建一个项目命名为CodeUin.Dapper,只用来提供接口,为业务层服务。
- Entities
- 存放实体类
- IRepository
- 存放仓库接口
- Repository
- 存放仓库接口实现类
- BaseModel
- 实体类的基类,用来存放通用字段
- DataBaseConfig
- 数据访问配置类
- IRepositoryBase
- 存放最基本的仓储接口 增删改查等
- RepositoryBase
- 基本仓储接口的具体实现
创建BaseModel基类
该类存放在项目的根目录下,主要作用是将数据库实体类中都有的字段独立出来。
1 | c#复制代码using System; |
创建DataBaseConfig类
该类存放在项目的根目录下,我这里使用的是MySQL,需要安装以下依赖包,如果使用的其他数据库,自行安装对应的依赖包即可。
该类具体代码如下:
1 | c#复制代码using MySql.Data.MySqlClient; |
创建IRepositoryBase类
该类存放在项目的根目录下,存放常用的仓储接口。
1 | c#复制代码using System; |
创建RepositoryBase类
该类存放在项目的根目录下,是IRepositoryBase类的具体实现。
1 | c#复制代码using Dapper; |
好了,基础类基本已经定义完成。下面将新建一个Users类,并定义几个常用的接口。
创建Users实体类
该类存放在Entities文件夹中,该类继承BaseModel。
1 | c#复制代码namespace CodeUin.Dapper.Entities |
创建IUserRepository类
该类存放在IRepository文件夹中,继承IRepositoryBase,并定义了额外的接口。
1 | c#复制代码using CodeUin.Dapper.Entities; |
创建UserRepository类
该类存放在Repository文件夹中,继承RepositoryBase, IUserRepository ,是IUserRepository类的具体实现。
1 | c#复制代码using CodeUin.Dapper.Entities; |
大功告成,接下来需要手动创建数据库和表结构,不能像使用EF那样自动生成了,使用Dapper基本上是要纯写SQL的,如果想像EF那样使用,就要额外的安装一个扩展 Dapper.Contrib。
数据库表结构如下,比较简单。
1 | sql复制代码DROP TABLE IF EXISTS `Users`; |
好了,数据访问层大概就这样子了,下面来看看应用层的具体实现方式。
应用程序层
创建一个WebApi项目,主要对外提供Api接口服务,具体结构如下。
- Autofac
- 存放IOC 依赖注入的配置项
- AutoMapper
- 存放实体对象映射关系的配置项
- Controllers
- 控制器,具体业务逻辑也将写在这
- Fliters
- 存放自定义的过滤器
- Helpers
- 存放本层中用到的一些帮助类
- Models
- 存放输入/输出/DTO等实体类
好了,结构大概就是这样。错误优先,先处理程序异常,和集成日志程序吧。
自定义异常处理
在Helpers文件夹中创建一个ErrorHandingMiddleware中间件,添加扩展方法ErrorHandlingExtensions,在Startup中将会使用到。
1 | c#复制代码using Microsoft.AspNetCore.Builder; |
然后在 Startup 的 Configure 方法中添加 app.UseErrorHandling() ,当程序发送异常时,会走我们的自定义异常处理。
1 | c#复制代码public void Configure(IApplicationBuilder app, IWebHostEnvironment env) |
日志程序
我这里使用的是NLog,需要在项目中先安装依赖包。
首先在项目根目录创建一个 nlog.config 的配置文件,具体内容如下。
1 | xml复制代码<?xml version="1.0" encoding="utf-8" ?> |
更多配置信息可以直接去官网查看 nlog-project.org
最后,在 Program 入口文件中集成 Nlog
1 | c#复制代码using Autofac.Extensions.DependencyInjection; |
现在,我们可以直接使用NLog了,使用方法可以查看上面的 ErrorHandlingMiddleware 类中有使用到。
依赖注入
将使用 Autofac 来管理类之间的依赖关系,Autofac 是一款超级赞的.NET IoC 容器 。首先我们需要安装依赖包。
在 项目根目录的 Autofac 文件夹中新建一个 CustomAutofacModule 类,用来管理我们类之间的依赖关系。
1 | c#复制代码using Autofac; |
在 Startup 类中添加方法
1 | c#复制代码public void ConfigureContainer(ContainerBuilder builder) |
实体映射
将使用 Automapper 帮我们解决对象映射到另外一个对象中的问题,比如这种代码。
1 | c#复制代码// 如果有几十个属性是相当的可怕的 |
先安装依赖包
在项目根目录的 AutoMapper 文件夹中 新建 AutoMapperConfig 类,来管理我们的映射关系。
1 | c#复制代码using AutoMapper; |
在 Startup 文件的 ConfigureServices 方法中 添加 services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()) 即可。
使用JWT
下面将集成JWT,来处理授权等信息。首先,需要安装依赖包。
修改 appsttings.json 文件,添加 Jwt 配置信息。
1 | c#复制代码{ |
最后,在 Startup 类的 ConfigureServices 方法中添加 Jwt 的使用。
1 | c#复制代码 services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |
好了,最终我们的 Startup 类是这样子的,关于自定义的参数验证后面会讲到。
1 | c#复制代码using Autofac; |
新建实体类
我将新建三个实体类,分别是 UserLoginModel 用户登录,UserRegisterModel 用户注册,UserModel 用户基本信息。
UserLoginModel 和 UserRegisterModel 将根据我们在属性中配置的特性自动验证合法性,就不需要在控制器中单独写验证逻辑了,极大的节省了工作量。
1 | c#复制代码using System; |
验证器
在项目根目录的 Filters 文件夹中 添加 ValidateModelAttribute 文件夹,将在 Action 请求中先进入我们的过滤器,如果不符合我们定义的规则将直接输出错误项。
具体代码如下。
1 | c#复制代码using Microsoft.AspNetCore.Mvc; |
添加自定义验证特性
有时候我们需要自己额外的扩展一些规则,只需要继承 ValidationAttribute 类然后实现 IsValid 方法即可,比如我这里验证了中国的手机号码。
1 | c#复制代码using System.ComponentModel.DataAnnotations; |
实现登录注册
我们来实现一个简单的业务需求,用户注册,登录,和获取用户信息,其他的功能都大同小异,无非就是CRUD!。
接口我们在数据服务层已经写好了,接下来是处理业务逻辑的时候到了,将直接在 Controllers 中编写。
新建一个控制器 UsersController ,业务很简单,不过多介绍了,具体代码如下。
1 | c#复制代码using System; |
最后,来测试一下我们的功能,首先是注册。
先来验证一下我们的传入的参数是否符合我们定义的规则。
输入一个错误的邮箱号试试看!
ok,没有问题,和我们在 UserRegisterModel 中 添加的验证特性返回结果一致,最后我们测试一下完全符合规则的情况。
最后,注册成功了,查询下数据库也是存在的。
我们来试试登录接口,在调用登录接口之前我们先来测试一下我们的配置的权限验证是否已经生效,在不登录的情况下直接访问获取用户信息接口。
直接访问会返回未授权,那是因为我们没有登录,自然也就没有 Token,目前来看是没问题的,但要看看我们传入正确的Token 是否能过权限验证。
现在,我们需要调用登录接口,登录成功后会返回一个Token,后面的接口请求都需要用到,不然会无权限访问。
先来测试一下密码错误的情况。
返回正确,符合我们的预期结果,下面将试试正确的密码登录,看是否能够返回我们想要的结果。
登录成功,接口也返回了我们预期的结果,最后看看生成的 token 是否按照我们写的逻辑那样,存一份到 redis 当中。
也是没有问题的,和我们预想的一样。
下面将携带正确的 token 请求获取用户信息的接口,看看是否能够正确返回。
获取用户信息的接口不会携带任何参数,只会在请求头的 Headers 中 添加 Authorization ,将我们正确的 token 传入其中。
能够正确获取到我们的用户信息,也就是说我们的权限这一块也是没有问题的了,下面将使用 Docker 打包部署到 Linux 服务器中。
打包部署
在项目的根目录下添加 Dockerfile 文件,内容如下。
1 | sql复制代码#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. |
在 Dockerfile 文件的目录下运行打包命令
1 | cmd复制代码# 在当前文件夹(末尾的句点)中查找 Dockerfile |
最后,将我们保存的镜像通过上传的服务器后导入即可。
通过 ssh 命令 连接服务器,在刚上传包的目录下执行导入命令。
1 | cmd复制代码# 加载镜像 |
到此为止,我们整个部署工作已经完成了,最后在请求服务器的接口测试一下是否ok。
最终的结果也是ok的,到此为止,我们所有基础的工作都完成了,所有的代码存储在 github.com/xiazanzhang… 中,如果对你有帮助的话可以参考一下。
本文转载自: 掘金