
1. .NET对象转JSON的常见方式概述在.NET开发中对象与JSON之间的转换是日常开发中最基础也最频繁的操作之一。无论是Web API的数据传输、配置文件读写还是缓存数据处理JSON序列化都扮演着关键角色。作为一名长期使用.NET的开发者我经历过各种序列化场景也踩过不少坑。今天就来系统梳理一下.NET中对象转JSON的几种主流方式以及它们各自的适用场景和性能特点。JSONJavaScript Object Notation作为一种轻量级的数据交换格式具有易于阅读和编写、便于机器解析和生成等优点。在.NET生态中微软官方和社区提供了多种JSON序列化方案每种方案都有其设计哲学和优化方向。从早期的JavaScriptSerializer到现在的System.Text.Json.NET的JSON序列化能力在不断进化。2. 主流JSON序列化方案详解2.1 System.Text.Json.NET Core 3.0System.Text.Json是.NET Core 3.0开始引入的高性能JSON序列化库现已成为.NET平台默认的JSON处理方案。它的设计目标就是提供高性能、低内存分配的序列化能力。基本使用方法using System.Text.Json; var person new Person { Name 张三, Age 30 }; string json JsonSerializer.Serialize(person);配置选项示例var options new JsonSerializerOptions { PropertyNamingPolicy JsonNamingPolicy.CamelCase, // 属性名驼峰式命名 WriteIndented true, // 美化输出 IgnoreNullValues true // 忽略null值 }; string json JsonSerializer.Serialize(person, options);性能特点比Newtonsoft.Json快约1.5-2倍内存分配减少30-50%支持Utf8JsonReader/Utf8JsonWriter进行底层操作提示对于高性能场景建议重用JsonSerializerOptions实例因为每次创建新实例会有初始化开销。2.2 Newtonsoft.JsonJson.NETNewtonsoft.Json是.NET生态中最流行的第三方JSON库功能丰富且成熟稳定。虽然现在有了官方解决方案但在很多复杂场景下仍然是首选。基本序列化using Newtonsoft.Json; var person new Person { Name 李四, Age 25 }; string json JsonConvert.SerializeObject(person);高级配置var settings new JsonSerializerSettings { Formatting Formatting.Indented, NullValueHandling NullValueHandling.Ignore, ContractResolver new CamelCasePropertyNamesContractResolver(), Converters { new StringEnumConverter() } // 枚举转字符串 }; string json JsonConvert.SerializeObject(person, settings);特色功能完善的类型处理多态序列化LINQ to JSONJObject/JArray灵活的转换器系统JsonConverter强大的错误处理机制2.3 JavaScriptSerializer传统ASP.NET这是.NET Framework早期内置的JSON序列化器现在基本已被取代但在一些遗留系统中还能见到。使用示例using System.Web.Script.Serialization; var serializer new JavaScriptSerializer(); string json serializer.Serialize(new { Name 王五, Age 28 });特点依赖System.Web.Extensions程序集功能相对简单性能较差不推荐在新项目中使用2.4 DataContractJsonSerializer基于WCF数据契约的序列化器适合需要严格契约控制的场景。基本用法using System.Runtime.Serialization.Json; var serializer new DataContractJsonSerializer(typeof(Person)); using var stream new MemoryStream(); serializer.WriteObject(stream, person); string json Encoding.UTF8.GetString(stream.ToArray());特点需要为类添加[DataContract]和[DataMember]属性对序列化过程有更严格的控制性能中等接口设计较为繁琐2.5 Utf8Json第三方高性能库Utf8Json是一个专注于极致性能的第三方JSON库特别适合高吞吐量场景。使用示例using Utf8Json; var person new Person { Name 赵六, Age 35 }; byte[] jsonBytes JsonSerializer.Serialize(person); string json JsonSerializer.ToJsonString(person);性能优势零内存分配的序列化直接处理UTF8字节避免编码转换支持异步IO操作3. 深度对比与选型建议3.1 功能对比表特性System.Text.JsonNewtonsoft.JsonJavaScriptSerializerDataContractJsonSerializer默认包含.NET Core 3.0需NuGet安装.NET Framework.NET Framework性能高中低中配置灵活性中高低中循环引用处理有限支持完善支持不支持有限支持多态支持有限完善不支持支持注释处理不支持支持不支持不支持日期格式处理严格ISO8601灵活可配置简单可配置3.2 性能基准测试数据通过BenchmarkDotNet测试10000次序列化的结果越小越好库平均时间(ms)内存分配(MB)System.Text.Json4512Utf8Json388Newtonsoft.Json8222DataContractJson12035JavaScriptSerializer180503.3 选型建议新项目首选System.Text.Json官方维护持续优化性能优异内存效率高与.NET平台深度集成复杂场景选择Newtonsoft.Json需要处理多态类型需要更灵活的配置选项需要处理非标准JSON格式极致性能场景Utf8Json超高吞吐量需求微服务间通信需要异步序列化遗留系统维护.NET Framework项目可继续使用JavaScriptSerializerWCF相关项目使用DataContractJsonSerializer4. 高级应用与最佳实践4.1 自定义转换器实现当默认序列化行为不满足需求时可以创建自定义转换器。以下是System.Text.Json的示例public class DateTimeConverter : JsonConverterDateTime { public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { return DateTime.ParseExact(reader.GetString(), yyyy-MM-dd, CultureInfo.InvariantCulture); } public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString(yyyy-MM-dd)); } } // 使用方式 var options new JsonSerializerOptions { Converters { new DateTimeConverter() } }; string json JsonSerializer.Serialize(data, options);4.2 处理循环引用循环引用是对象图中常见的挑战。Newtonsoft.Json处理起来更简单var settings new JsonSerializerSettings { PreserveReferencesHandling PreserveReferencesHandling.Objects, ReferenceLoopHandling ReferenceLoopHandling.Serialize };System.Text.Json需要更多手动控制var options new JsonSerializerOptions { ReferenceHandler ReferenceHandler.Preserve };4.3 性能优化技巧重用JsonSerializerOptions避免重复创建配置对象使用源生成器.NET 6[JsonSerializable(typeof(Person))] public partial class MyJsonContext : JsonSerializerContext {} // 使用生成的序列化代码 string json JsonSerializer.Serialize(person, MyJsonContext.Default.Person);对于大型对象考虑使用流式APIawait JsonSerializer.SerializeAsync(stream, largeObject);避免频繁反序列化考虑使用DOM模型JsonDocument/JObject4.4 安全注意事项防范JSON注入始终验证外部输入的JSON处理敏感数据使用[JsonIgnore]排除敏感属性类型安全反序列化时明确指定预期类型资源释放及时释放JsonDocument/Utf8JsonReader等资源5. 常见问题与解决方案5.1 日期时间处理问题不同库对DateTime的处理方式不同// System.Text.Json默认严格ISO8601格式 var options new JsonSerializerOptions { // 自定义日期格式 Converters { new DateTimeConverter(yyyy-MM-dd HH:mm:ss) } }; // Newtonsoft.Json更灵活 var settings new JsonSerializerSettings { DateFormatString yyyy-MM-dd HH:mm:ss };5.2 大小写策略冲突统一命名策略很重要// System.Text.Json options.PropertyNamingPolicy JsonNamingPolicy.CamelCase; // Newtonsoft.Json settings.ContractResolver new CamelCasePropertyNamesContractResolver();5.3 忽略null值控制是否序列化null值// System.Text.Json options.DefaultIgnoreCondition JsonIgnoreCondition.WhenWritingNull; // Newtonsoft.Json settings.NullValueHandling NullValueHandling.Ignore;5.4 处理只读属性默认情况下大多数序列化器只处理可写属性// System.Text.Json options.IncludeFields true; // 包含字段 options.PropertyNameCaseInsensitive true; // 不区分大小写 // Newtonsoft.Json settings.ContractResolver new DefaultContractResolver { SerializeCompilerGeneratedMembers true };5.5 多语言兼容性处理不同文化背景的数字、日期格式var options new JsonSerializerOptions { NumberHandling JsonNumberHandling.AllowReadingFromString, Encoder JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 处理非ASCII字符 };6. 实际应用场景示例6.1 Web API开发在ASP.NET Core中System.Text.Json已是默认序列化器// 在Startup中配置全局选项 services.AddControllers() .AddJsonOptions(options { options.JsonSerializerOptions.PropertyNamingPolicy JsonNamingPolicy.CamelCase; options.JsonSerializerOptions.WriteIndented true; });6.2 配置文件读写使用JSON作为应用配置var config new { AppName MyApp, ConnectionStrings new { Default Server... } }; string json JsonSerializer.Serialize(config); File.WriteAllText(appsettings.json, json); // 读取 var options new JsonSerializerOptions { PropertyNameCaseInsensitive true }; var config JsonSerializer.DeserializeAppConfig( File.ReadAllText(appsettings.json), options);6.3 分布式缓存Redis等缓存中的对象序列化// 使用高性能的System.Text.Json byte[] serialized JsonSerializer.SerializeToUtf8Bytes(cacheItem); await cache.StringSetAsync(key, serialized, expiry); // 反序列化 var data await cache.StringGetAsync(key); var item JsonSerializer.DeserializeCacheItem(data);6.4 消息队列通信在微服务间传递消息// 生产端 var message new OrderMessage { OrderId 123, Status Created }; string json JsonSerializer.Serialize(message); await rabbitMq.PublishAsync(json); // 消费端 var options new JsonSerializerOptions { Converters { new MessageConverter() } }; var message JsonSerializer.DeserializeOrderMessage(json, options);7. 版本兼容性与升级建议7.1 从Newtonsoft.Json迁移到System.Text.Json迁移步骤分析现有代码中的Json.NET特定功能逐步替换为System.Text.Json的等效实现使用兼容性开关处理差异options.Converters.Add(new JsonStringEnumConverter()); options.PropertyNameCaseInsensitive true; options.NumberHandling JsonNumberHandling.AllowReadingFromString;7.2 .NET Framework到.NET Core的过渡混合使用策略#if NETCOREAPP using System.Text.Json; #else using Newtonsoft.Json; #endif7.3 未来发展趋势源生成器将成为默认推荐方式更强大的异步流式处理更完善的LINQ集成更好的AOT编译支持8. 调试与性能分析技巧8.1 诊断序列化问题使用JsonDocument分析JSON结构using JsonDocument doc JsonDocument.Parse(json); foreach (JsonProperty prop in doc.RootElement.EnumerateObject()) { Console.WriteLine(${prop.Name}: {prop.Value.ValueKind}); }8.2 性能分析工具BenchmarkDotNet精确测量各种场景下的性能Memory Profiler分析内存分配情况PerfView深入分析CPU使用情况8.3 日志记录最佳实践记录序列化过程中的关键信息try { var obj JsonSerializer.DeserializeT(json); } catch (JsonException ex) { _logger.LogError(ex, JSON解析失败。原始数据: {Json}, json); throw; }9. 扩展与自定义9.1 创建工厂模式封装public interface IJsonSerializer { string SerializeT(T obj); T DeserializeT(string json); } public class SystemTextJsonSerializer : IJsonSerializer { private readonly JsonSerializerOptions _options; public SystemTextJsonSerializer(JsonSerializerOptions options null) { _options options ?? new JsonSerializerOptions { PropertyNameCaseInsensitive true }; } public string SerializeT(T obj) JsonSerializer.Serialize(obj, _options); public T DeserializeT(string json) JsonSerializer.DeserializeT(json, _options); }9.2 实现动态代理序列化public class DynamicProxyConverterT : JsonConverterT { public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 实现动态代理逻辑 } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { // 实现动态代理逻辑 } }9.3 集成到DI容器services.AddSingletonJsonSerializerOptions(provider { return new JsonSerializerOptions { PropertyNamingPolicy JsonNamingPolicy.CamelCase, Converters { new CustomConverter() } }; }); services.AddSingletonIJsonSerializer, SystemTextJsonSerializer();10. 总结与个人经验分享在实际项目中我通常会根据以下因素选择序列化方案项目类型新项目优先System.Text.Json遗留项目可能继续使用Json.NET性能需求高吞吐场景考虑Utf8Json或System.Text.Json的源生成器功能复杂度需要处理多态、复杂类型图时Json.NET更省心团队熟悉度避免引入团队不熟悉的技术增加维护成本一个实用的技巧是对于核心高频调用的接口可以单独为它们创建专用的JsonSerializerContext这样能获得最佳性能。而对于开发期频繁变化的DTO使用动态生成的选项更灵活。最后提醒一点无论选择哪种序列化方式都要确保在整个应用中保持一致性。混用不同的JSON库往往会导致难以调试的问题特别是在微服务架构中。