迁移至System.Text.Json后,如何批量配置源生成序列化兼容AOT?
解决System.Text.Json源生成序列化批量配置问题
方案1:利用程序集级别的JsonSerializable特性(.NET 7+)
从.NET 7开始,JsonSerializable支持直接标记在程序集上,一次性指定整个命名空间或程序集内的所有类型,不用逐个手动添加特性。
比如要包含某个命名空间下的所有类型:
[assembly: JsonSerializable(typeof(MyLibrary.Models.*))]
如果要包含整个程序集的类型:
[assembly: JsonSerializable(Assembly = typeof(MyLibrary.SomeType).Assembly)]
还可以结合规则筛选,比如只包含特定基类的子类:
[assembly: JsonSerializable(typeof(MyBaseType), TypeInfoResolver = typeof(PolymorphicTypeResolver))]
注意:这个特性会自动纳入指定范围内的所有可序列化类型,无需逐个声明。
方案2:用MSBuild任务自动生成上下文类
可以写一个自定义MSBuild任务,在编译前扫描项目中的目标类型,自动生成带有所有JsonSerializable特性的MyLibraryContext类文件。
示例MSBuild任务代码:
public class GenerateJsonContextTask : Task { [Required] public string OutputPath { get; set; } [Required] public string AssemblyPath { get; set; } public override bool Execute() { var assembly = Assembly.LoadFrom(AssemblyPath); // 筛选需要序列化的类型,这里以指定命名空间、排除抽象类和泛型定义为例 var targetTypes = assembly.GetTypes() .Where(t => t.Namespace.StartsWith("MyLibrary.Models") && !t.IsAbstract && !t.IsGenericTypeDefinition); var codeBuilder = new StringBuilder(); codeBuilder.AppendLine("using System.Text.Json.Serialization;"); codeBuilder.AppendLine(); codeBuilder.AppendLine("internal partial class MyLibraryContext : JsonSerializerContext"); codeBuilder.AppendLine("{"); foreach (var type in targetTypes) { codeBuilder.AppendLine($" [JsonSerializable(typeof({type.FullName}))]"); } codeBuilder.AppendLine("}"); File.WriteAllText(OutputPath, codeBuilder.ToString()); return true; } }
在项目文件中引用这个任务,配置它在编译前执行,就能自动生成上下文类文件。
方案3:自定义源代码生成器
编写一个.NET源代码生成器,在编译时扫描项目中的语法树或程序集,自动生成JsonSerializationContext的部分类,批量添加JsonSerializable特性。
核心实现步骤:
- 创建类库项目,引用
Microsoft.CodeAnalysis.CSharp和Microsoft.CodeAnalysis.Analyzers。 - 实现
ISourceGenerator接口,在Execute方法中扫描符合条件的类型。 - 生成包含所有
JsonSerializable特性的代码,并注入到编译过程中。
示例生成器核心代码片段:
[Generator] public class JsonContextGenerator : ISourceGenerator { public void Initialize(GeneratorInitializationContext context) { // 初始化逻辑,比如注册语法接收器 } public void Execute(GeneratorExecutionContext context) { // 筛选目标类型,这里以类名以Model结尾为例 var targetTypes = context.Compilation.SyntaxTrees .SelectMany(tree => tree.GetRoot().DescendantNodes()) .OfType<ClassDeclarationSyntax>() .Where(c => c.Identifier.Text.EndsWith("Model")) .Select(c => context.Compilation.GetSemanticModel(c.SyntaxTree).GetDeclaredSymbol(c)) .OfType<INamedTypeSymbol>(); var code = new StringBuilder(); code.AppendLine("using System.Text.Json.Serialization;"); code.AppendLine("internal partial class MyLibraryContext : JsonSerializerContext {"); foreach (var type in targetTypes) { code.AppendLine($" [JsonSerializable(typeof({type.ToDisplayString()}))]"); } code.AppendLine("}"); context.AddSource("MyLibraryContext.g.cs", code.ToString()); } }
把这个生成器打包成NuGet包,引用到类库项目中,编译时就会自动生成对应的上下文类。
内容的提问来源于stack exchange,提问作者Aleksey Usatov
相关产品推荐
相关产品推荐

