You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:00:30