ASP.NET Core 5中JsonConverter反序列化TimeSpan时的属性名获取问题
解决ASP.NET Core 5 MVC中TimeSpan反序列化时获取属性名的问题
问题根源
自定义TimeSpan转换器触发时,JsonReader默认指向的是属性值(比如序列化后的数字),而非属性名。这是因为转换器在读取属性值的阶段才会被调用,此时Reader的位置已经跳过了属性名节点。
针对System.Text.Json的解决方案
ASP.NET Core 5默认使用System.Text.Json,以下是两种获取属性名的可行方法:
方法1:回退Reader到属性名节点
在转换器的Read方法中,先临时回退到属性名节点读取名称,再回到值节点继续处理:
using System.Text.Json; using System.Text.Json.Serialization; public class TimeSpanToStringConverter : JsonConverter<TimeSpan> { public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { string propertyName = null; var initialTokenType = reader.TokenType; // 如果当前指向值节点,回退到属性名节点 if (initialTokenType != JsonTokenType.PropertyName) { if (reader.Read() && reader.TokenType == JsonTokenType.PropertyName) { propertyName = reader.GetString(); // 回到值节点继续处理 reader.Read(); } } else { propertyName = reader.GetString(); reader.Read(); } // 这里可以根据propertyName做差异化处理 Console.WriteLine($"当前处理属性:{propertyName}"); // 处理TimeSpan反序列化逻辑 if (reader.TokenType == JsonTokenType.Number) { return TimeSpan.FromTicks(reader.GetInt64()); } else if (reader.TokenType == JsonTokenType.String) { return TimeSpan.Parse(reader.GetString()); } throw new JsonException($"无法将{reader.TokenType}类型转换为TimeSpan"); } public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString()); } }
方法2:通过Reader.Path提取属性名
利用JsonReader.Path获取当前属性的完整路径,再截取最后一段作为属性名:
public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // 从路径中提取属性名,比如路径为"$[0].PromotionDuration",取最后一段 string fullPath = reader.Path; string propertyName = fullPath.Split('.').Last(); // 后续反序列化逻辑同上... }
转换器注册方式
- 属性级注册:直接标记在目标属性上
public class ProductPromotionModel { public int Id { get; set; } [JsonConverter(typeof(TimeSpanToStringConverter))] public TimeSpan PromotionDuration { get; set; } // 其他属性 }
- 全局注册:在
Startup.cs中配置
services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new TimeSpanToStringConverter()); });
若使用Newtonsoft.Json的适配方案
如果项目引入了Microsoft.AspNetCore.Mvc.NewtonsoftJson包,转换器写法略有不同,可直接通过JsonReader.Path提取属性名:
using Newtonsoft.Json; using Newtonsoft.Json.Converters; public class TimeSpanToStringConverter : JsonConverter<TimeSpan> { public override TimeSpan ReadJson(JsonReader reader, Type objectType, TimeSpan existingValue, bool hasExistingValue, JsonSerializer serializer) { string propertyName = reader.Path.Split('.').Last(); if (reader.TokenType == JsonToken.Integer) { return TimeSpan.FromTicks((long)reader.Value); } else if (reader.TokenType == JsonToken.String) { return TimeSpan.Parse((string)reader.Value); } throw new JsonException($"无法转换为TimeSpan"); } public override void WriteJson(JsonWriter writer, TimeSpan value, JsonSerializer serializer) { writer.WriteValue(value.ToString()); } }
全局注册方式:
services.AddControllers() .AddNewtonsoftJson(options => { options.SerializerSettings.Converters.Add(new TimeSpanToStringConverter()); });
内容的提问来源于stack exchange,提问作者JagathNalin
相关产品推荐
相关产品推荐

