.NET 6源代码生成器:跨项目从实体类生成DTO可行吗?
解决方案:基于服务端实体在共享项目生成DTO
核心目标:在Project C(共享项目)中借助Project B(服务端)的实体类,通过源代码生成器生成共用DTO,同时严格保证Project A(客户端)不直接依赖Project B。
以下是可落地的实现方案:
1. 配置项目依赖规则
- 让源代码生成器模块(可单独抽离为类库)仅在编译时引用Project B:目的是获取实体类的元数据,不会引入运行时依赖
- Project C的最终输出(生成的DTO类)不包含任何对Project B的引用,仅保留纯POCO结构
- Project A和Project B分别引用Project C,实现DTO的双向共用
2. 源代码生成器的具体实现步骤
步骤1:创建生成器项目
新建一个.NET类库项目(例如命名为EntityToDtoGenerator),添加Microsoft.CodeAnalysis.CSharp和Microsoft.CodeAnalysis.Analyzers的NuGet包,同时添加对Project B的项目引用。
步骤2:编写DTO生成逻辑
通过Roslyn API扫描Project B中的实体类(可通过自定义特性标记需要生成DTO的实体),自动生成对应DTO类并输出到Project C。核心代码示例:
[Generator] public class EntityDtoGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { } public void Execute(GeneratorExecutionContext context) { // 筛选标记了[GenerateDto]特性的实体类 var targetEntities = context.Compilation.SyntaxTrees .SelectMany(tree => tree.GetRoot().DescendantNodes()) .OfType<ClassDeclarationSyntax>() .Where(cls => cls.AttributeLists.Any(attr => attr.Attributes.Any(a => a.Name.ToString() == "GenerateDto"))); foreach (var entity in targetEntities) { // 提取实体的属性,生成DTO代码 var propertyCode = string.Join("\n ", entity.Members.OfType<PropertyDeclarationSyntax>() .Where(p => !p.AttributeLists.Any(attr => attr.Attributes.Any(a => a.Name.ToString() == "IgnoreDto"))) .Select(p => $"public {p.Type} {p.Identifier} {{ get; set; }}")); var dtoSource = $@" namespace SharedProject.Dtos; public class {entity.Identifier.Text}Dto {{ {propertyCode} }}"; // 将生成的代码添加到Project C的编译输出 context.AddSource($"{entity.Identifier.Text}Dto.g.cs", dtoSource); } } }
步骤3:关联生成器到Project C
在Project C的项目文件中添加生成器引用,配置为编译时依赖:
<ItemGroup> <ProjectReference Include="..\EntityToDtoGenerator\EntityToDtoGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> </ItemGroup>
3. 关键注意事项
- 隔离运行时依赖:确保生成的DTO类不包含任何EF特有的属性或引用,只保留需要暴露给客户端的字段
- 精准筛选实体:给Project B中需要生成DTO的实体标记自定义特性(如
[GenerateDto]),同时用[IgnoreDto]标记不需要暴露的属性 - 避免导航属性泄露:生成器要过滤掉EF实体中的导航属性,防止客户端获取不必要的关联数据
内容的提问来源于stack exchange,提问作者Florent
相关产品推荐
相关产品推荐

