项目结构重构
1.1 Electric.DbMigrator 存在的问题
我们先来看下,后台 API 项目的目录结构。
其中 Electric.DbMigrator,这个项目作用是用来做数据库迁移的,但是同时也会被其他项目引用,还有这个项目类型还是 Web API 类型的。所以存在以下的几个问题:
1、项目功能重合:数据库迁移和数据库访问;
2、发布:和 Electric.API 一样是 Web API 项目,无法发布。
3、配置文件重复,发布也会导致无法发布。
1.2 Electric.DbMigrator 重构
针对以上的问题,建议可以把 Electric.DbMigrator 拆为两个项目:Electric.DbMigrator、Electric.EntityFrameworkCore。
1、Electric.DbMigrator:数据库迁移相关的;
2、Electric.EntityFrameworkCore:项目数据库访问相关的。
1.2.1 新建项目 Electric.EntityFrameworkCore
在解决方案右键 =》新增项目 =》选择:类库,项目名称:Electric.EntityFrameworkCore。
配置选择如下:
1、框架:.Net 7.0
1.2.2 项目拆分
1、把 Electric.DbMigrator 中:ApplicationDbContext.cs 迁移至 Electric.****EntityFrameworkCore。
迁移后的目录:
2、Electric.DbMigrator 添加项目依赖:Electric.****EntityFrameworkCore。
更改代码的使用,把项目 Electric.DbMigrator 中:所有 Electric.DbMigrator 改为 Electric.EntityFrameworkCore。
3、Electric.****EntityFrameworkCore 添加项目依赖:Electric.Entity。
4、依赖包
Electric.****EntityFrameworkCore 添加依赖包:
1、Microsoft.AspNetCore.Identity.EntityFrameworkCore:Identity 核心库;
以下截图,就是安装完成后的截图,我这边安装当前最新版本:7.0.5。
5、更新项目依赖
Electric.Repository 删除 Electric.DbMigrator 项目的引用,添加 Electric.EntityFrameworkCore 项目引用。
更改代码的使用,把项目 Electric.Repository 和 Electric.API 中:所有 Electric.DbMigrator 改为 Electric.EntityFrameworkCore。
6、此时我们再次发布,就能发布成功了。
1.2.3 数据库迁移修改
虽然可以发布成功,但是数据库迁移这边还存在问题。
注意默认项目:选择 Electric.DbMigrator,并把 Electric.DbMigrator 设置为默认启动项目。
打开:程序包管理器控制台,操作步骤:菜单栏找到:工具 =》NuGet 包管理器 =》程序包管理器控制台。
异常错误:
您的目标项目 “Electric.DbMigrator” 与迁移程序集 “Electric.EntityFrameworkCore” 不匹配。请更改目标项目或更改迁移程序集。
所以,在项目入口 Programe.cs 的数据库注入代码,要指定程序集。
修改代码如下:
//数据库上下文注入
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
//启用的数据库类型
var provider = builder.Configuration.GetValue<string>("DataProvider");
switch (provider)
{
case "MsSql":
var msSqlConnection = builder.Configuration.GetConnectionString("MsSqlConnection") ?? throw new InvalidOperationException("MsSqlConnection在appsettings.json未发现");
options.UseSqlServer(msSqlConnection, b => b.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName));
break;
case "MySql":
var mySqlConnection = builder.Configuration.GetConnectionString("MySqlConnection") ?? throw new InvalidOperationException("MySqlConnection在appsettings.json未发现");
//MySql需要传入版本,ServerVersion.AutoDetect根据连接字符串自动获取
options.UseMySql(mySqlConnection, ServerVersion.AutoDetect(mySqlConnection), b => b.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName));
break;
}
});
我们再次执行数据库迁移,这时候就可以成功了。
Program.cs 重构
2.1 Program.cs 存在的问题
Electric.API 项目中的 Program.cs,代码总行数已经超过了 150 行,为了还会持续增加越来越多的功能,所以我们可以进行重构。
重构思路步骤:
-
Program.cs 包含多个功能模块:JWT、数据库注入、Swagger、跨域、AutoMapper 等等;
-
根据功能模块,提取代码;通过扩展方法来重构。
2.2 新建扩展方法
在项目 Electric.API 项目,文件夹 Extensions 新增以下类:
- AutoMapperExtension:AutoMapper 相关扩展;
- CorsOriginsExtension:跨域相关扩展;
- DbContextExtension:数据库相关扩展;
- JWTExtension:JWT 相关扩展;
- MVCExtension:MVC 相关扩展;
- RepositoryExtension:Repository 相关扩展;
- SwaggerGenExtension:SwaggerGen 相关扩展。
并根据功能模块,迁移代码。
重构原则:
- 一个功能模块,对应一个扩展方法类;
- 扩展方法命名格式:AddElectric + 功能名,区分框架默认的中间件服务。
// 将服务添加到容器中。
builder.AddElectricControllers();
public static void AddElectricControllers(this WebApplicationBuilder builder){} // 扩展方法类
// Swagger/OpenAPI 服务
builder.AddElectricSwaggerGen();
public static void AddElectricSwaggerGen(this WebApplicationBuilder builder){}
//数据库上下文注入
builder.AddElectricDbContext();
public static void AddElectricDbContext(this WebApplicationBuilder builder){}
//添加jwt验证
builder.AddElectricJWT();
public static void AddElectricJWT(this WebApplicationBuilder builder){}
//添加注入
builder.AddElectricRepository();
public static void AddElectricRepository(this WebApplicationBuilder builder){}
//AutoMapper依赖注入
builder.AddElectricAutoMapper();
public static void AddElectricAutoMapper(this WebApplicationBuilder builder){}
Program.cs 重构后完整代码:
using Electric.API.Extensions;
var builder = WebApplication.CreateBuilder(args);
// 将服务添加到容器中。
builder.AddElectricControllers();
// Swagger/OpenAPI 服务
builder.AddElectricSwaggerGen();
//数据库上下文注入
builder.AddElectricDbContext();
//添加jwt验证
builder.AddElectricJWT();
//添加注入
builder.AddElectricRepository();
//AutoMapper依赖注入
builder.AddElectricAutoMapper();
//跨域配置
var eleAllowSpecificOrigins = "EleAllowSpecificOrigins";
builder.AddElectricCorsOrigins(eleAllowSpecificOrigins);
var app = builder.Build();
//跨域配置
app.UseCors(eleAllowSpecificOrigins);
// 配置HTTP请求管道。
if (app.Environment.IsDevelopment())
{
//开发环境下,才开启Swagger
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
重构后 Program.cs 的代码行数,只有 46 行,并且逻辑比较单一,方便我们阅读。
appsetting 配置提取常量
3.1 常量字符串问题
我们项目中,为了获取 appsettings.json
的配置,都会在代码中,指定相应的 key,来获取配置的值。
这样存在以下问题:
1、如果我们修改了 appsettings.json 的 key 名称,对应的代码都需要修改;
2、如果代码有多处使用,会导致修改遗漏。
3.2 定义常量字符串
在 Electric.API 的文件夹 Auth,添加 AppSettings 类:用于定义 appsettings.json 相关常量 Key。
完整代码如下:
/// <summary>
/// appsettings.json相关常量Key
/// </summary>
public static class AppSettings
{
/// <summary>
/// DataProvider
/// </summary>
public const string DataProvider = "DataProvider";
/// <summary>
/// MsSqlConnection
/// </summary>
public const string MsSqlConnection = "MsSqlConnection";
/// <summary>
/// MySqlConnection
/// </summary>
public const string MySqlConnection = "MySqlConnection";
/// <summary>
/// CorsOrigins
/// </summary>
public const string CorsOrigins = "CorsOrigins";
/// <summary>
/// Authentication
/// </summary>
public const string Authentication = "Authentication";
/// <summary>
/// JwtBearer
/// </summary>
public const string JwtBearer = "JwtBearer";
/// <summary>
/// Issuer
/// </summary>
public const string Issuer = "Issuer";
/// <summary>
/// Audience
/// </summary>
public const string Audience = "Audience";
/// <summary>
/// SecurityKey
/// </summary>
public const string SecurityKey = "SecurityKey";
}
修改对应的代码:
修改的地方:扩展方法 Extensions、AuthsController 登录方法。