WCF JSON Serialization error with DateTime.MinVal and UTC

本文介绍了一种解决WCF JSON Web服务中遇到的DateTime.MinValue序列化问题的方法。该问题导致了SerializationException错误,解决方案是在序列化前指定DateTime.Kind为Utc。
I came across the following error today in is WCF JSON web service:
SerializationException: DateTime values that are greater than DateTime.MaxValue or smaller than DateTime.MinValue when converted to UTC cannot be serialized to JSON.
The solution took me a while to get my head round, so I thought I should share it. The clue was a  StackOverflow post specifying the error and its cause.


This was compounded by the fact that the WCF service was returning a rather obscure 504 error, namely:
ReadResponse() failed: The server did not return a response for this request.
The error was not being picked up and returned as a service fault, so I switched  WCF tracing on. The error message was then visible in the logs:

<Exception>
<ExceptionType>System.Runtime.Serialization.SerializationException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>DateTime values that are greater than DateTime.MaxValue or smaller than DateTime.MinValue when converted to UTC cannot be serialized to JSON.</Message>

The bottom line is that if you have a DateTime property that is not set, it will be defaulted to DateTime.MinVal when serialized. However, DateTime.MinVal does not have a  DateTimeKind specified, which is the default.

This causes a problem with the serializer because it does not treat the MinVal as UTC. If you are in a timezone + GMT (East), then  this is going to cause you a problem, and you'll get the error above. This is very nicely described by  Adam Robinson:
If your time zone is GMT+1, then the UTC value of DateTime.MinValue in your time zone is going to be an hour less than DateTime.MinValue.
In my case I had a bunch of DTO objects being passed back as JSON. The serializer would hit the defaulted DateTime value and error. the solution was simple:

foreach (var dto in dtos)
{
    dto.DateStart = DateTime.SpecifyKind(dto.DateStart, DateTimeKind.Utc);
}

The alternative is to stop DateTimes being left empty. In my case an Automapper misconfiguration on the developer's part. If you have the potential for empty DateTime properties, then maybe consider making them nullable.


http://benpowell.soup.io/post/156011793/WCF-JSON-Serialization-error-with-DateTime-MinVal

<think>我们被要求对比System.Runtime.Serialization.Json和System.Text.Json这两个用于JSON序列化的库。根据引用内容,我们可以总结如下: 引用[1]提到:虽然System.Runtime.Serialization.Json可以在C#中用于JSON的序列化和反序列化,但在大多数情况下,更推荐使用Newtonsoft.Json.NET Core的System.Text.Json。 引用[2]展示了System.Text.Json的用法和System.Runtime.Serialization.Json作为第三种方式的存在。 引用[3]提供了System.Text.Json.Serialization的使用示例,说明它是System.Text.Json的一部分,用于序列化和反序列化自定义类型。 引用[4]指出:System.Text.Json以其卓越的性能和现代特性成为大多数场景的首选。 因此,我们可以从以下几个方面进行对比: 1. **来源和命名空间** - System.Runtime.Serialization.Json:位于`System.Runtime.Serialization`命名空间,是.NET Framework的一部分,最初为WCF设计。 - System.Text.Json:位于`System.Text.Json`命名空间,是.NET Core 3.0及更高版本(包括.NET 5+)中引入的,旨在提供高性能的JSON处理。 2. **性能** - 根据引用[4],System.Text.Json具有卓越的性能。这是因为System.Text.Json从头开始设计,专注于性能和低内存分配,特别是在高吞吐量场景中(如Web服务器)表现更佳。 3. **功能和易用性** - System.Runtime.Serialization.Json:使用数据契约模型(通过`[DataContract]`和`[DataMember]`属性控制序列化),功能相对基础,自定义能力有限。 - System.Text.Json:提供了更丰富的功能,包括更灵活的命名策略、对异步序列化的支持、内置的UTF-8读写器等。同时,它默认使用属性(property)名称,也可以通过属性(如`[JsonPropertyName]`)进行自定义。 4. **版本兼容性** - System.Runtime.Serialization.Json:支持较早的.NET Framework(包括.NET 4.x),但无法利用最新的性能优化。 - System.Text.Json:需要.NET Core 3.0+或.NET 5+,因此对于旧项目(特别是.NET Framework 4.x)需要升级才能使用。 5. **安全性** - System.Text.Json在设计时考虑了安全性,例如默认情况下对反序列化器有更多的安全限制(如不允许注释、尾随逗号等),以减少漏洞。 6. **推荐场景** - 根据引用[1]和引用[4],对于新项目,尤其是基于.NET Core或.NET 5+的,推荐使用System.Text.Json。如果项目仍在使用.NET Framework 4.x且无法升级,则可以考虑使用System.Runtime.Serialization.Json,但更推荐使用Newtonsoft.Json(因为功能更丰富),除非有特定限制。 下面用示例代码对比两者: **System.Runtime.Serialization.Json 示例:** ```csharp using System.Runtime.Serialization.Json; using System.IO; [DataContract] public class Person { [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } } // 序列化 var person = new Person { Name = "Alice", Age = 30 }; DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Person)); using (MemoryStream stream = new MemoryStream()) { serializer.WriteObject(stream, person); string json = Encoding.UTF8.GetString(stream.ToArray()); } // 反序列化 byte[] jsonBytes = Encoding.UTF8.GetBytes(json); using (MemoryStream stream = new MemoryStream(jsonBytes)) { Person deserialized = (Person)serializer.ReadObject(stream); } ``` **System.Text.Json 示例:** ```csharp using System.Text.Json; public class Person { public string Name { get; set; } public int Age { get; set; } } // 序列化 var person = new Person { Name = "Alice", Age = 30 }; string json = JsonSerializer.Serialize(person); // 反序列化 Person deserialized = JsonSerializer.Deserialize<Person>(json); ``` 对比可见,System.Text.Json的API更为简洁,不需要数据契约属性(除非需要自定义),并且直接操作字符串,不需要处理流(除非需要性能优化)。 **总结:** | 特性 | System.Runtime.Serialization.Json | System.Text.Json | |------------------|-------------------------------------------|--------------------------------------------| | **命名空间** | `System.Runtime.Serialization.Json` | `System.Text.Json` | | **性能** | 一般 | 高(低内存分配,优化算法)[^4] | | **功能** | 基础(依赖数据契约) | 丰富(命名策略、异步、读取器等) | | **易用性** | 中等(需要流操作和数据契约) | 高(直接字符串操作,默认行为友好) | | **兼容性** | .NET Framework 4.x+ | .NET Core 3.0+, .NET 5+ | | **安全性** | 一般 | 较高(默认更严格) | | **推荐场景** | 遗留系统(.NET Framework)且不能升级 | 新项目(.NET Core/5+) | 因此,在可能的情况下,建议优先选择System.Text.Json,特别是在性能要求高或使用新框架的项目中。对于维护旧项目,若不能升级目标框架,则可以考虑继续使用System.Runtime.Serialization.Json,但需注意其局限性。 §§相关问题§§ 1. 如何在.NET Framework项目中使用System.Text.Json? 2. Newtonsoft.Json与System.Text.Json有何区别? 3. 如何优化System.Text.Json的序列化性能?[^4] </think>### System.Runtime.Serialization.Json vs System.Text.Json 对比分析 #### 1. **来源与兼容性** - **System.Runtime.Serialization.Json** - 属于 .NET Framework 4.x 内置组件(命名空间:`System.Runtime.Serialization.Json`) - 主要服务于 WCF 数据契约场景,兼容 .NET Framework 4.0+ - **System.Text.Json** - .NET Core 3.0+ 引入(命名空间:`System.Text.Json`) - 需通过 NuGet 包在 .NET Framework 4.6.1+ 中使用(包名:`System.Text.Json`)[^1][^4] #### 2. **性能对比** | 指标 | System.Runtime.Serialization.Json | System.Text.Json | |--------------------|-----------------------------------|------------------------| | 序列化速度 | 较慢(基于反射和流操作) | **快 1.5-2 倍**(基于 Span\<T\>)[^4] | | 内存分配 | 高(需 `MemoryStream` 缓冲) | **低**(直接处理 UTF-8)[^4] | | 大型数据处理 | 易出现性能瓶颈 | 优化了大型 JSON 处理 | #### 3. **功能差异** | 特性 | System.Runtime.Serialization.Json | System.Text.Json | |--------------------------|-------------------------------------------|--------------------------------------| | **依赖属性** | 需 `[DataContract]`/`[DataMember]` 属性 | 默认使用所有公共属性(支持 `[JsonIgnore]`) | | **自定义命名** | 通过 `[DataMember(Name="...")]` | `[JsonPropertyName("...")]` | | **枚举处理** | 默认序列化为数字 | 支持数字和字符串(`JsonStringEnumConverter`) | | **异步序列化** | ❌ 不支持 | ✔️ 支持 `SerializeAsync()` | | **注释和尾逗号** | ❌ 不支持 | ✔️ 可配置(`JsonSerializerOptions`) | #### 4. **代码示例对比** ```csharp // ===== System.Runtime.Serialization.Json ===== [DataContract] public class Person { [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } } // 序列化 var serializer = new DataContractJsonSerializer(typeof(Person)); using (var stream = new MemoryStream()) { serializer.WriteObject(stream, person); string json = Encoding.UTF8.GetString(stream.ToArray()); } // ===== System.Text.Json ===== public class Person { public string Name { get; set; } public int Age { get; set; } } // 序列化 (直接操作字符串) string json = JsonSerializer.Serialize(person); // 异步序列化到文件 await using (var file = File.Create("person.json")) { await JsonSerializer.SerializeAsync(file, person); } ``` #### 5. **安全性** - **System.Runtime.Serialization.Json** 存在反序列化风险(如类型注入漏洞) - **System.Text.Json** 默认禁用不安全特性(如对象引用处理),提供 `JsonSerializerOptions` 控制安全行为[^4] #### 6. **推荐场景** | 场景 | 推荐库 | |------------------------------|----------------------------| | .NET Framework 4.x 旧项目 | `System.Runtime.Serialization.Json` | | 高性能 Web API/微服务 | **`System.Text.Json`**(首选)[^1][^4] | | 需要严格安全控制 | **`System.Text.Json`** | | 处理大型 JSON 文件 (>10MB) | **`System.Text.Json`**(异步流支持) | > 💡 **总结**:在新项目或可升级环境中,`System.Text.Json` 是更优选择。对于旧版 .NET Framework 项目,若无法引入新依赖,可继续使用 `System.Runtime.Serialization.Json`,但需注意性能和安全性限制[^1][^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值