using Dpz.Core.Hangfire;
using Hangfire;
namespace Dpz.Core.WebApi.Controllers;
/// <summary>
/// 源码管理
/// </summary>
[ApiController, Route("api/[controller]")]
public class CodeController(ICodeFileSystemEntryService codeFileSystemEntryService) : ControllerBase
{
/// <summary>
/// 获取源码树节点
/// </summary>
/// <returns></returns>
[HttpGet]
[ProducesResponseType<CodeNoteTree>(StatusCodes.Status200OK)]
public async Task<IActionResult> GetCodeNotes([FromQuery] params string[] path)
{
var tree = await codeFileSystemEntryService.BuildCodeNoteTreeAsync(path);
if (
tree is { CodeContainer.CodeContent: not null, FileName: not null }
&& await codeFileSystemEntryService.ShouldAnalyzeAsync(
tree.CurrentPaths.ToArray(),
tree.FileName,
tree.CodeContainer
)
)
{
var parentPath = tree.ParentPaths.ToArray();
BackgroundJob.Enqueue<AnalyzeCodeActivator>(x =>
x.AnalyzeAsync(tree.CodeContainer.CodeContent, parentPath, tree.FileName)
);
}
return Ok(tree);
}
/// <summary>
/// 搜索
/// </summary>
/// <param name="keyword"></param>
/// <returns></returns>
[HttpGet("search")]
[ProducesResponseType<CodeNoteTree>(StatusCodes.Status200OK)]
public async Task<IActionResult> Search([FromQuery][Required] string keyword)
{
if (string.IsNullOrWhiteSpace(keyword))
{
return Ok(CodeNoteTree.FromSearch([]));
}
var matchList = await codeFileSystemEntryService.SearchAsync(keyword);
var model = CodeNoteTree.FromSearch(matchList);
return Ok(model);
}
/// <summary>
/// 保存源码说明
/// </summary>
/// <returns></returns>
[HttpPost, Authorize(Policy = "System")]
[ProducesResponseType<CodeNoteTree>(StatusCodes.Status204NoContent)]
[ProducesResponseType<CodeNoteTree>(StatusCodes.Status401Unauthorized)]
public async Task<IActionResult> SaveNote([FromBody] CodeSaveDto model)
{
var saved = await codeFileSystemEntryService.SaveDescriptionAsync(
model.Path,
model.Name,
model.Note
);
if (!saved)
{
return BadRequest("path not exists");
}
return NoContent();
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
下面以简洁明了的方式解释这段控制器代码的功能、各端点的行为及关键点(均为 C# ASP.NET Core WebAPI 代码):
总体说明
- 这是一个用于“源码管理/源码说明”的 API 控制器,路由为 api/Code([ApiController], Route("api/[controller]"))。
- 依赖注入了 ICodeFileSystemEntryService(构造器注入的简写语法:CodeController(ICodeFileSystemEntryService ...))。
- 使用了异步方法(Task
)并结合 Hangfire(BackgroundJob.Enqueue)来在后台队列分析源码内容。 - 代码中带了 Swagger/响应类型注解([ProducesResponseType])和授权约束([Authorize(Policy = "System")])。
各个动作说明
- GetCodeNotes ([HttpGet])
路径:GET api/Code
参数:可变长度的 query 参数 path(params string[] path)。调用示例:GET api/Code?path=a&path=b 或 GET api/Code?path=/foo。
行为:
- 调用 codeFileSystemEntryService.BuildCodeNoteTreeAsync(path) 构建源码树/节点(返回 CodeNoteTree)。
- 如果返回的 tree 满足:tree.CodeContainer.CodeContent 不为空 且 tree.FileName 不为空,并且 service 的 ShouldAnalyzeAsync(...) 返回 true,则将一次分析任务入队到 Hangfire:
- BackgroundJob.Enqueue
(x => x.AnalyzeAsync(tree.CodeContainer.CodeContent, parentPath, tree.FileName)) - 也就是说把当前文件内容、父路径数组和文件名提交给 AnalyzeCodeActivator 的 AnalyzeAsync 在后台处理(异步、持久化的后台作业)。
- BackgroundJob.Enqueue
- 最后返回 Ok(tree)(200 + JSON)。
关键点:
- 通过 C# 的属性模式匹配判断 CodeContainer.CodeContent / FileName 是否为 null(现代写法)。
- parentPath 使用 tree.ParentPaths.ToArray()(传递父路径数组给后台任务)。
- Hangfire 的表达式入队要求方法签名和类型可被序列化调用,AnalyzeCodeActivator 需要是可解析的服务/类型并有公有方法 AnalyzeAsync。
- Search ([HttpGet("search")])
- 路径:GET api/Code/search
- 参数:[FromQuery] [Required] string keyword(必须在查询字符串中提供 keyword)。
- 行为:
- 如果 keyword 为空或只含空白,直接返回一个空的搜索结果 CodeNoteTree.FromSearch([])(Ok)。
- 否则调用 codeFileSystemEntryService.SearchAsync(keyword) 得到匹配列表,然后用 CodeNoteTree.FromSearch(matchList) 构建模型并返回 Ok(model)。
- 作用:对源码/说明内容进行关键字搜索并返回树/匹配结构。
- SaveNote ([HttpPost], [Authorize(Policy = "System")])
- 路径:POST api/Code
- 授权:只有满足名为 "System" 的策略的用户才可调用。
- 请求体:[FromBody] CodeSaveDto model(包含 Path、Name、Note 等字段)。
- 行为:
- 调用 codeFileSystemEntryService.SaveDescriptionAsync(model.Path, model.Name, model.Note) 以保存源码说明/注释。
- 如果返回 false(保存失败/路径不存在),返回 BadRequest("path not exists")。
- 成功则返回 NoContent()(204)。
- 作用:保存/更新源码项的说明文本。
额外说明 / 注意事项
- Swagger/响应注解:[ProducesResponseType] 用于 API 文档,某些地方(比如将类型与 204 一起标注)语义上可能不严谨(204 无内容通常不带响应体)。
- params string[] path 的绑定:调用时可重复传递 query 参数名 path 多次,或在客户端构造数组形式;需要注意前端如何传参。
- Hangfire 后台任务:
- 使用 BackgroundJob.Enqueue 会把任务放入队列并立即返回。要确保 AnalyzeCodeActivator 与 AnalyzeAsync 在应用范围内可被解析并且方法参数可以被序列化。
- 并发/幂等性:GetCodeNotes 里会在满足条件时多次入队分析(如果前端频繁请求同一文件可能产生多次任务),若不希望重复分析应在 ShouldAnalyzeAsync 或任务端做去重/防护。
总结
- 该控制器提供:获取源码树(并在必要时异步分析源码)、关键词搜索源码、保存源码说明的 API。配合 ICodeFileSystemEntryService 实现源码文件系统的构建、搜索与保存,并借助 Hangfire 做异步分析任务的执行。
评论加载中...