反序列化ASP.NET生成的JSON DateTime时出错的技术问询
问题分析与解决方案
核心问题根源
你遇到的差异本质是数据传输方式的区别:
- 常规API端点接收的是请求体JSON,ASP.NET Core会直接解析原始请求内容,不会做URL编码转换,因此序列化后的标准日期格式(如
2023-05-24T20:20:46.9351772+01:00)能被框架默认反序列化逻辑正确处理。 - 而你当前是从QueryString参数中提取JSON,QueryString中的
+符号会被自动解析为空格,导致日期格式变成2023-05-24T20:20:46.9351772 01:00——这种格式不符合JSON标准的日期规范,直接触发反序列化失败。
你自定义的转换器之所以无效,是因为传入的日期字符串里的偏移符号已被替换为空格,DateTime.Parse无法识别带空格的偏移格式。
解决方案
方案1:修复URL编码问题(推荐)
这是最根本的解决方式,QueryString参数必须经过URL编码才能保证特殊字符不被篡改。
MAUI端发送时编码JSON:
string json = JsonSerializer.Serialize(new MyDto(DateTime.Now)); // 对JSON进行URL编码,避免+符号被解析为空格 string encodedJson = Uri.EscapeDataString(json); // 发送时将encodedJson作为data参数的值传递
API中间件接收时解码:
string encodedData = httpContext.Request.Query["data"].ToString(); // 先解码还原原始JSON string json = Uri.UnescapeDataString(encodedData); MyDto dto = JsonHelpers.Deserialise<MyDto>(json);
方案2:统一使用UTC日期格式,规避偏移符号冲突
强制序列化和反序列化都使用UTC格式的日期,彻底避免偏移符号的URL编码问题。
MAUI端序列化配置:
var serializeOptions = new JsonSerializerOptions { DateTimeFormat = new DateTimeFormatInfo { // 使用UTC后缀Z的格式,无需偏移符号 FullDateTimePattern = "yyyy-MM-dd'T'HH:mm:ss.fffffffZ" } }; string json = JsonSerializer.Serialize(new MyDto(DateTime.Now.ToUniversalTime()), serializeOptions);
API端反序列化配置:
var deserializeOptions = new JsonSerializerOptions { DateTimeFormat = new DateTimeFormatInfo { FullDateTimePattern = "yyyy-MM-dd'T'HH:mm:ss.fffffffZ" } }; MyDto dto = JsonSerializer.Deserialize<MyDto>(json, deserializeOptions); // 如果JsonHelpers.Deserialise支持传入配置,直接传递deserializeOptions即可
方案3:修改自定义转换器兼容空格偏移格式
如果无法修改发送逻辑,可以调整自定义转换器,先修复被篡改的日期字符串:
public class CustomDateTimeConverter : JsonConverter<DateTime?> { const string Format = "yyyy-MM-dd hh:mm:ss.fffffff zzz"; public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 将空格替换回+符号,还原原始偏移格式 var dateStr = reader.GetString()?.Replace(' ', '+'); return DateTime.Parse(dateStr, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal); } public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) => writer.WriteStringValue(value?.ToUniversalTime().ToString(Format, CultureInfo.InvariantCulture)); }
反序列化时记得传入带该转换器的配置:
var options = new JsonSerializerOptions { Converters = { new CustomDateTimeConverter() } }; MyDto dto = JsonHelpers.Deserialise<MyDto>(json, options);
内容的提问来源于stack exchange,提问作者DelphiNewbie
相关产品推荐
相关产品推荐

