需求分析与场景定义
- 明确代码生成器的目标:生成实体类、API控制器、DTO等常见场景
- 典型应用场景:快速开发CRUD功能、减少重复编码工作
- 核心需求:可配置性、模板灵活性、与项目结构无缝集成
具体实现可参考NetCoreKevin的kevin.CodeGenerator模块
基于.NET构建的企业级SaaS智能应用架构,采用前后端分离设计,具备以下核心特性:
前端技术:
- Vue3前端框架
- IDS4单点登录系统
- 一库多租户解决方案
- 多级缓存机制
- CAP事件集成
- SignalR实时通信
- 领域驱动设计
- AI智能体框架
- RabbitMQ消息队列
- 项目地址:github:https://github.com/junkai-li/NetCoreKevin
Gitee: https://gitee.com/netkevin-li/NetCoreKevin
第一步:配置模板
模板配置示例如下图所示:
创建kevin.CodeGenerator模块
ICodeGeneratorService接口定义
usingkevin.CodeGenerator.Dto;usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;namespacekevin.CodeGenerator{publicinterfaceICodeGeneratorService{/// <summary>/// 获取区域名称列表/// </summary>/// <returns></returns>Task<List<string>>GetAreaNames();/// <summary>/// 获取区域名称下面的表列表/// </summary>/// <returns></returns>Task<List<EntityItemDto>>GetAreaNameEntityItems(stringareaName);/// <summary>/// 生成代码/// </summary>/// <param name="entityItems"></param>/// <returns></returns>Task<bool>BulidCode(List<EntityItemDto>entityItems);}}CodeGeneratorService实现
usingkevin.CodeGenerator.Dto;usingMicrosoft.CodeAnalysis;usingMicrosoft.CodeAnalysis.CSharp;usingMicrosoft.CodeAnalysis.CSharp.Syntax;usingMicrosoft.Extensions.Options;usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Reflection.Metadata;usingSystem.Text;usingstaticMicrosoft.CodeAnalysis.CSharp.SyntaxTokenParser;namespacekevin.CodeGenerator{publicclassCodeGeneratorService:ICodeGeneratorService{privateCodeGeneratorSetting_config;publicCodeGeneratorService(IOptionsMonitor<CodeGeneratorSetting>config){_config=config.CurrentValue;}publicasyncTask<List<string>>GetAreaNames(){return_config.CodeGeneratorItems.Select(t=>t.AreaName).ToList();}publicasyncTask<List<EntityItemDto>>GetAreaNameEntityItems(stringareaName){vararea=_config.CodeGeneratorItems.FirstOrDefault(t=>t.AreaName==areaName);if(area!=default){varentityItems=newList<EntityItemDto>();varpath="..\\..\\"+area.AreaPath.Trim().Replace(".","\\");// 遍历路径下的所有 .cs 文件if(!Directory.Exists(path)){thrownewArgumentException($"CodeGeneratorSetting配置:{areaName}{area.AreaPath}不存在");}else{varcsFiles=Directory.GetFiles(path,"*.cs",SearchOption.AllDirectories);foreach(varfileincsFiles){// 读取文件内容varcode=File.ReadAllText(file);vartree=CSharpSyntaxTree.ParseText(code);varroot=(CompilationUnitSyntax)tree.GetRoot();// 查找所有类声明varclassDeclarations=root.DescendantNodes().OfType<ClassDeclarationSyntax>();foreach(varclassDeclarationinclassDeclarations){// 检查类是否有 Table 特性if(classDeclaration.AttributeLists.Any(list=>list.Attributes.Any(attr=>attr.Name.ToString()=="Table"))){stringdescription="";// 检查类是否有 Description 特性vardescriptionAttr=classDeclaration.AttributeLists.SelectMany(list=>list.Attributes).FirstOrDefault(attr=>attr.Name.ToString()=="Description");if(descriptionAttr!=null){// 获取特性参数值vararg=descriptionAttr.ArgumentList?.Arguments.FirstOrDefault();if(arg?.ExpressionisLiteralExpressionSyntaxliteral){description=literal.Token.ValueText;}}entityItems.Add(newEntityItemDto{AreaName=area.AreaName,EntityName=classDeclaration.Identifier.Text,Description=$"{file}:{description}"});}}}returnentityItems;}}returnnewList<EntityItemDto>();}publicasyncTask<bool>BulidCode(List<EntityItemDto>entityItems){//获取对应的模板文件variRpTemplate=GetBuildCodeTemplate("IRp");varrpTemplate=GetBuildCodeTemplate("Rp");variServiceTemplate=GetBuildCodeTemplate("IService");varservice=GetBuildCodeTemplate("Service");foreach(variteminentityItems){vararea=_config.CodeGeneratorItems.FirstOrDefault(t=>t.AreaName==item.AreaName);if(area!=default){if(item.EntityName.StartsWith("T",StringComparison.OrdinalIgnoreCase)){item.EntityName=item.EntityName.Substring(1);}WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.IRpBulidPath}},iRpTemplate,$"../../{area.IRpBulidPath.Trim().Replace(".","\\")}/I{item.EntityName}Rp.cs");WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.RpBulidPath}},rpTemplate,$"../../{area.RpBulidPath.Trim().Replace(".","\\")}/{item.EntityName}Rp.cs");WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.IServiceBulidPath}},iServiceTemplate,$"../../{area.IServiceBulidPath.Trim().Replace(".","\\")}/I{item.EntityName}Service.cs");WriteCode(newDictionary<string,string>{{"%entityName%",item.EntityName},{"%namespacePath%",area.ServiceBulidPath}},service,$"../../{area.ServiceBulidPath.Trim().Replace(".","\\")}/{item.EntityName}Service.cs");}}returntrue;}/// <summary>/// 获取对应模板文件/// </summary>/// <param name="name"></param>/// <returns></returns>privatestringGetBuildCodeTemplate(stringname){returnFile.ReadAllText("..\\..\\"+"Kevin\\kevin.Module\\kevin.CodeGenerator\\BuildCodeTemplate\\"+name+".txt",encoding:Encoding.UTF8);}/// <summary>/// 生成文件和代码/// </summary>/// <param name="paramters"></param>/// <param name="content"></param>/// <param name="savePath"></param>privatevoidWriteCode(Dictionary<string,string>paramters,stringcontent,stringsavePath){foreach(variteminparamters){content=content.Replace(item.Key,item.Value);}vardir=Path.GetDirectoryName(savePath);if(!Directory.Exists(dir)){Directory.CreateDirectory(dir);}if(File.Exists(savePath)){Console.WriteLine($"文件{savePath}已存在,跳过生成!");}else{File.WriteAllText(savePath,content,Encoding.UTF8);}}}}CodeGeneratorSettingDto
namespacekevin.CodeGenerator.Dto{publicclassCodeGeneratorSetting{/// <summary>/// 配置文件相关信息/// </summary>publicList<CodeGeneratorItem>CodeGeneratorItems{get;set;}=new();}publicclassCodeGeneratorItem{/// <summary>/// 区域/// </summary>publicstringAreaName{get;set;}="";/// <summary>/// 数据库实体类路径/// </summary>publicstringAreaPath{get;set;}="";/// <summary>/// 仓储接口生成路径/// </summary>publicstringIRpBulidPath{get;set;}="";/// <summary>/// 仓储生成路径/// </summary>publicstringRpBulidPath{get;set;}="";/// <summary>/// 服务接口生成路径/// </summary>publicstringIServiceBulidPath{get;set;}="";/// <summary>/// 服务生成路径/// </summary>publicstringServiceBulidPath{get;set;}="";}}配置Json文件
////代码生成器配置 .转换成/时要和路径一致 请配置好命名空间和路径对应关系"CodeGeneratorSetting":{"CodeGeneratorItems":[{"AreaName":"App.WebApi.v1",//项目命名"AreaPath":"App.Domain.Entities",//实体类路径"IRpBulidPath":"App.Domain.Interfaces.Repositorie.v1",//仓储接口命名空间和路径"RpBulidPath":"App.RepositorieRps.Repositories.v1",//仓储命名空间和路径"IServiceBulidPath":"App.Domain.Interfaces.Services.v1",//服务接口命名空间和路径"ServiceBulidPath":"App.Application.Services.v1"//服务命名空间和路径}]}服务注入
services.AddKevinCodeGenerator(options=>{varsettings=Configuration.GetRequiredSection("CodeGeneratorSetting").Get<CodeGeneratorSetting>()!;options.CodeGeneratorItems=settings.CodeGeneratorItems;});使用