新模块开发指南
本文介绍如何按照 FreeKit Pro Modules 的约定从零创建并注册一个新业务模块。
目录结构约定
src/Services/<ModuleName>/
└── FreeKit.<ModuleName>/ # 模块主项目
├── <ModuleName>ModuleStartup.cs # 模块入口(必须)
├── Domain/ # 实体、领域逻辑
├── Application/ # 应用服务、用例
├── Contracts/ # DTOs、接口(共享给客户端)
├── Controllers/ # REST 控制器
└── Models/ # FreeSql 实体配置(可选)
第 1 步 — 创建项目
cd src/Services
mkdir Notification
cd Notification
dotnet new classlib -n FreeKit.Notification --framework net10.0
在 .csproj 中添加对 BuildingBlocks 的引用:
<ItemGroup>
<ProjectReference Include="..\..\..\BuildingBlocks\IGeekFan.FreeKit.Infrastructure\IGeekFan.FreeKit.Infrastructure.csproj" />
</ItemGroup>
第 2 步 — 实现 IModuleStartup
每个模块必须实现 IGeekFan.FreeKit.Modularity.IModuleStartup:
using IGeekFan.FreeKit.Modularity;
namespace FreeKit.Notification;
public class NotificationModuleStartup : IModuleStartup
{
/// <summary>
/// 注册服务到 DI 容器
/// </summary>
public void ConfigureServices(IServiceCollection services, IConfiguration c)
{
// 注册 AutoMapper
services.AddAutoMapper(typeof(NotificationModuleStartup).Assembly);
// 读取模块配置
services.Configure<NotificationOption>(c.GetSection("Notification"));
// 注册业务服务
services.AddScoped<INotificationService, NotificationService>();
}
/// <summary>
/// 配置中间件 / 同步 FreeSql 表结构
/// </summary>
public void Configure(WebApplication app, IWebHostEnvironment env)
{
IFreeSql fsql = app.Services.GetRequiredService<IFreeSql>();
fsql.CodeFirst.SyncStructure(
typeof(NotificationRecord)
);
}
}
第 3 步 — 定义实体
使用 FreeSql 的 [Table] 特性,无需继承任何基类(但可继承框架提供的 AuditEntity):
using FreeSql.DataAnnotations;
namespace FreeKit.Notification.Domain;
[Table(Name = "notification_record")]
public class NotificationRecord
{
[Column(IsPrimary = true, IsIdentity = true)]
public long Id { get; set; }
public Guid UserId { get; set; }
public string Title { get; set; } = string.Empty;
public string Content { get; set; } = string.Empty;
public bool IsRead { get; set; }
[Column(ServerTime = DateTimeKind.Utc, CanUpdate = false)]
public DateTime CreateTime { get; set; }
}
第 4 步 — 编写 Controller
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
namespace FreeKit.Notification.Controllers;
[ApiController]
[Route("api/notification")]
[Authorize]
public class NotificationController : ControllerBase
{
private readonly INotificationService _service;
public NotificationController(INotificationService service)
=> _service = service;
[HttpGet]
public async Task<IActionResult> GetList([FromQuery] int page = 1, [FromQuery] int size = 20)
{
var result = await _service.GetListAsync(page, size);
return Ok(result);
}
[HttpPost("{id}/read")]
public async Task<IActionResult> MarkRead(long id)
{
await _service.MarkReadAsync(id);
return Ok();
}
}
第 5 步 — 注册到 E.cs
在 src/Services/Host/FreeKit.DI/E.cs 的 Modules 字典中添加一行:
// FreeKit.DI/E.cs
using FreeKit.Notification; // <-- 添加 using
public static readonly Dictionary<string, Type> Modules = new(StringComparer.OrdinalIgnoreCase)
{
{ "identity", typeof(IdentityModuleStartup) },
// ... 其他模块
{ "notification", typeof(NotificationModuleStartup) }, // <-- 添加此行
};
同时在 FreeKit.DI.csproj 中添加项目引用:
<ProjectReference Include="..\..\Notification\FreeKit.Notification\FreeKit.Notification.csproj" />
第 6 步 — 添加配置(可选)
在 appsettings.Development.json 中添加模块配置段:
{
"Notification": {
"MaxRetryCount": 3,
"DefaultExpireDays": 30
}
}
对应的 Options 类:
public class NotificationOption
{
public int MaxRetryCount { get; set; } = 3;
public int DefaultExpireDays { get; set; } = 30;
}
模块禁用
只需从 E.cs 的 Modules 字典中删除对应的键即可,无需修改任何其他代码。
约定总结
| 规则 | 说明 |
|---|---|
| 命名 | <Entity>Service、I<Entity>Service、<Entity>Dto、<Entity>Req |
| 启动类 | 必须实现 IModuleStartup,命名为 <Module>ModuleStartup |
| 建表 | 在 Configure() 中调用 fsql.CodeFirst.SyncStructure(...) |
| DI 注册 | 在 ConfigureServices() 中注册,不使用 Program.cs |
| 配置 | 使用 IOptions<T> 模式,Options 类命名为 <Feature>Option |