常见问题 FAQ
快速解决 FreeKitModules 开发中的常见问题
📋 目录
环境配置问题
❓ 启动时报错:Unable to find package 'xxx'
问题原因:NuGet 包未正确还原
解决方案:
# 清理并重新还原
dotnet clean
dotnet restore
dotnet build
如果仍然失败,检查 NuGet 源配置:
dotnet nuget list source
❓ 端口 5001 被占用
错误信息:System.IO.IOException: Failed to bind to address https://127.0.0.1:5001
解决方案 1 - 修改端口:
编辑 appsettings.json:
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"Https": {
"Url": "https://localhost:5002"
}
}
}
}
解决方案 2 - 释放端口(Windows):
# 查找占用端口的进程
netstat -ano | findstr :5001
# 终止进程(替换 PID)
taskkill /PID 12345 /F
数据库相关问题
❓ 数据库连接失败
错误信息:Authentication to host 'localhost' for user 'root' using method 'caching_sha2_password' failed
解决方案:
- 检查连接字符串(
appsettings.Development.json):
{
"ConnectionStrings": {
"DefaultDB": "0",
"MySql": "Data Source=localhost;Port=3306;User ID=root;Password=YourPassword;Initial Catalog=freekit;Charset=utf8mb4;SslMode=none;"
}
}
- 确认 MySQL 正在运行:
# Docker 环境
docker ps | grep mysql
# 本地 Windows 服务
Get-Service MySQL*
- 检查防火墙:确保 3306(或自定义)端口开放
❓ FreeSql 表结构未自动同步
问题原因:实体未注册到 CodeFirst.SyncStructure
解决方案:
在 Program.cs 或模块 Startup 中添加:
// 同步单个实体
fsql.CodeFirst.SyncStructure<Article>();
// 同步多个实体
fsql.CodeFirst.SyncStructure(
typeof(Article),
typeof(Comment),
typeof(User)
);
// 同步整个程序集
fsql.CodeFirst.SyncStructure(Assembly.GetExecutingAssembly().GetTypes());
注意:生产环境务必关闭自动同步:
fsql.CodeFirst.IsAutoSyncStructure = false;
❓ 数据库表已存在但字段未更新
问题原因:FreeSql 默认不修改已存在的字段
解决方案:
手动删除表或使用 SQL 脚本更新:
-- 添加新字段
ALTER TABLE cms_article ADD COLUMN NewColumn VARCHAR(100);
-- 修改字段类型
ALTER TABLE cms_article MODIFY COLUMN Title VARCHAR(500);
或在开发环境使用 IsSyncStructureToLower:
fsql.CodeFirst.IsSyncStructureToLower = true; // 强制同步
模块注册问题
❓ 启动时报错:Service 'xxx' is not registered
问题原因:模块注册顺序错误或缺少注册步骤
正确的模块注册顺序(必须按此顺序):
// 1. 程序集注册
List<Type> typeAssemblies = new List<Type>()
{
typeof(Program),
typeof(IApplicationService),
typeof(FreeKitModule),
typeof(CmsKitModuleStartup), // ← 确保添加了模块Startup
typeof(BasicIdentityModuleStartup)
};
containerBuilder.RegisterModule(new FreeKitModule(typeAssemblies.ToArray(), null));
containerBuilder.RegisterModule(new UnitOfWorkModule(typeAssemblies.ToArray(), null));
// 2. 服务依赖注入
services.AddModule<CmsKitModuleStartup>("module-cmskit", configuration);
services.AddModule<BasicIdentityModuleStartup>("module-basic-identity", configuration);
// 3. CAP 事件总线配置
var assemblies = new List<Assembly>
{
typeof(CmsKitModuleStartup).Assembly,
typeof(BasicIdentityModuleStartup).Assembly
};
services.AddKitCap(configuration).AddSubscriberAssembly(assemblies.ToArray());
// 4. Swagger 配置
var projectNames = new List<string>() { "FreeKit.CmsKit", "FreeKit.BasicIdentity" };
services.AddSwagger(configuration, projectNames);
检查清单:
- ✅ 步骤 1 必须在前
- ✅ 所有模块的 Startup 类都添加到 typeAssemblies
- ✅ AddModule 和 AddKitCap 使用相同的程序集列表
FreeSql 使用问题
❓ 查询时未过滤软删除数据
问题:查询结果包含 IsDeleted = true 的数据
解决方案:
使用 IAuditBaseRepository 或手动过滤:
// 方式1:使用 IAuditBaseRepository(推荐)
var articles = await _repository.Where(x => x.Status == 1).ToListAsync();
// IsDeleted 自动过滤
// 方式2:手动过滤
var articles = await fsql.Select<Article>()
.Where(x => !x.IsDeleted)
.ToListAsync();
❓ 审计字段未自动填充
问题:CreateTime、CreateUserId 等字段为空
检查:
- 实体是否继承
FullAuditEntity - 是否使用
IAuditBaseRepository - 当前用户信息是否正确获取
// 实体必须继承
public class Article : FullAuditEntity
{
// ...
}
// 使用审计仓储
private readonly IAuditBaseRepository<Article> _repository;
❓ 多租户数据未隔离
问题:查询到其他租户的数据
解决方案:
- 实体实现
ITenant接口:
public class Article : FullAuditEntity, ITenant
{
public Guid TenantId { get; set; }
}
- 配置全局过滤器:
fsql.GlobalFilter.Apply<ITenant>("TenantFilter", x => x.TenantId == currentTenantId);
CAP 事件总线问题
❓ CAP 事件未触发
常见原因:
- 未添加订阅程序集:
services.AddKitCap(configuration)
.AddSubscriberAssembly(typeof(CmsKitModuleStartup).Assembly); // ← 必须添加
- 订阅方法签名错误:
// ❌ 错误:缺少 [CapSubscribe] 特性
public Task HandleArticleCreated(ArticleDto dto) { }
// ✅ 正确
[CapSubscribe("cms.article.created")]
public Task HandleArticleCreated(ArticleDto dto) { }
- 事件名称不匹配:
// 发布
await _capPublisher.PublishAsync("cms.article.created", dto);
// 订阅(必须完全一致)
[CapSubscribe("cms.article.created")] // ← 确保名称相同
❓ CAP Dashboard 无法访问
检查配置:
services.AddCap(options =>
{
options.UseDashboard(); // ← 启用 Dashboard
// ...
});
app.UseCapDashboard(); // ← 注册中间件
访问地址:https://localhost:5001/cap
Redis 连接问题
❓ Redis 连接失败
错误信息:It was not possible to connect to the redis server(s)
解决方案:
- 检查 Redis 是否运行:
# Windows(如果使用 WSL)
wsl redis-cli ping
# 应返回 PONG
# Docker
docker ps | grep redis
- 检查连接字符串:
{
"Redis": {
"ConnectionString": "localhost:6379,password=,defaultDatabase=0"
}
}
- 防火墙检查:确保 6379 端口开放
❓ 缓存数据未生效
问题:修改数据后仍返回旧数据
解决方案:
手动清除缓存:
// 使用 IDistributedCache
await _cache.RemoveAsync($"Article:{articleId}");
// 使用 Redis 客户端
await _redisClient.DelAsync($"Article:{articleId}");
或使用缓存失效策略:
// 更新数据时自动清除缓存
await _repository.UpdateAsync(article);
await _cache.RemoveAsync($"Article:{article.Id}");
认证授权问题
❓ 401 Unauthorized 错误
常见原因:
- Token 未传递:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
-
Token 过期:检查
expires_in时间 -
JWT 配置错误:
{
"JWT": {
"SecretKey": "YourSecretKeyAtLeast32Characters!!",
"Issuer": "FreeKitModules",
"Audience": "FreeKitModules.API"
}
}
❓ 403 Forbidden 错误
问题原因:用户已认证但无权限
解决方案:
- 检查用户角色:
SELECT * FROM identity_user_role WHERE UserId = 'xxx';
- 检查权限策略:
[Authorize(Policy = "随笔列表")] // ← 确保用户有此权限
- 使用
[AllowAnonymous]测试:
[AllowAnonymous] // 暂时移除权限检查
public async Task<IActionResult> GetAsync() { }
性能优化问题
❓ 接口响应慢(>1s)
排查步骤:
- 检查数据库查询:
// 启用 SQL 日志
fsql.Aop.CrudBefore += (s, e) =>
{
Console.WriteLine($"SQL: {e.Sql}");
};
- 检查 N+1 查询:
// ❌ N+1 查询
var articles = await _repository.ToListAsync();
foreach (var article in articles)
{
article.User = await _userRepository.GetAsync(article.CreateUserId); // ← 每次查询
}
// ✅ Include 预加载
var articles = await fsql.Select<Article>()
.Include(x => x.User)
.ToListAsync();
- 添加缓存:
var cacheKey = $"HotArticles";
var articles = await _cache.GetOrCreateAsync(cacheKey, async entry =>
{
entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15);
return await _repository.Where(x => x.ViewHits > 1000).ToListAsync();
});
❓ 数据库索引未生效
检查索引:
-- 查看表索引
EXEC sp_helpindex 'cms_article';
-- 创建缺失索引
CREATE INDEX IX_Article_CreateTime ON cms_article(CreateTime DESC);
CREATE INDEX IX_Article_AuditStatus_CreateTime ON cms_article(AuditStatus, CreateTime DESC);
参考各模块的 EntityReference.md 查看推荐索引。
🔍 仍未解决?
- 查看日志:
logs/目录下的详细错误日志 - 搜索 Issues:https://gitee.com/your-repo/FreeKitModules/issues
- 提交新 Issue:提供错误日志、环境信息、复现步骤
- 加入讨论:https://gitee.com/your-repo/FreeKitModules/discussions
最后更新: 2025年11月24日