.NET中DateOnly序列化报错:无法将StartObject令牌转为字符串
解决DateOnlyJsonConverter中的"Cannot get the value of a token type 'StartObject' as a string."错误
问题分析
错误的核心原因是当前自定义转换器仅支持读取字符串格式的日期,但实际请求中DateOnly被序列化为了JSON对象(而非字符串)。当JsonReader遇到StartObject类型的Token时,直接调用reader.GetString()会抛出异常——该方法仅适用于String类型的Token。
修复方案
修改DateOnlyJsonConverter的Read方法,同时兼容字符串格式和JSON对象格式的DateOnly输入:
public class DateOnlyJsonConverter : JsonConverter<DateOnly> { private const string Format = "yyyy-MM-dd"; public override DateOnly Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 处理JSON对象格式的DateOnly(如{"Year":2024,"Month":5,"Day":20}) if (reader.TokenType == JsonTokenType.StartObject) { int year = 0, month = 0, day = 0; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) break; if (reader.TokenType == JsonTokenType.PropertyName) { var propName = reader.GetString(); reader.Read(); switch (propName) { case nameof(DateOnly.Year): year = reader.GetInt32(); break; case nameof(DateOnly.Month): month = reader.GetInt32(); break; case nameof(DateOnly.Day): day = reader.GetInt32(); break; } } } return new DateOnly(year, month, day); } // 处理字符串格式的DateOnly(如"2024-05-20") else if (reader.TokenType == JsonTokenType.String) { var dateStr = reader.GetString(); if (DateOnly.TryParseExact(dateStr, Format, CultureInfo.InvariantCulture, out DateOnly date)) { return date; } throw new JsonException($"无法将字符串'{dateStr}'转换为DateOnly类型,格式需为{Format}"); } throw new JsonException($"不支持的Token类型:{reader.TokenType}"); } public override void Write(Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString(Format, CultureInfo.InvariantCulture)); } }
额外优化建议
移除重复特性:你已经在
Program.cs中全局注册了转换器,无需再在CelestialObjectEntity和CelestialObjectDto的DiscoveryDate字段上添加[JsonConverter(typeof(DateOnlyJsonConverter))],避免重复处理引发潜在问题。规范请求格式:确保前端请求日期符合以下两种格式之一:
- 字符串格式:
"DiscoveryDate": "2024-05-20" - 对象格式:
"DiscoveryDate": {"Year":2024,"Month":5,"Day":20}
- 字符串格式:
优化异常反馈:控制器中直接返回
NoContent()不利于问题排查,建议返回带错误信息的BadRequest:catch (Exception ex) { return BadRequest(new { Message = "添加天体失败", Error = ex.Message }); }
内容的提问来源于stack exchange,提问作者antonio
相关产品推荐
相关产品推荐

