【问题标题】:define timespan format in .net 4.5 standard serializer在 .net 4.5 标准序列化程序中定义时间跨度格式
【发布时间】:2015-09-14 09:11:54
【问题描述】:

我有一个具有一些时间跨度属性的对象,我在我的 MVC 操作中使用 .net 序列化程序。(我的操作返回 JsonResult 类型) timeSpan Prop 像这样反序列化:

"EndTime":{"Hours":9,"Minutes":0,"Seconds":0,"Milliseconds":0,"Ticks":324000000000,"Days":0,"TotalDays":0.375,"TotalHours":9,"TotalMilliseconds":32400000,"TotalMinutes":540,"TotalSeconds":32400}

之后我在 Windows 应用程序中调用此操作,我需要使用 newtonesoft 反序列化此对象。 但我收到此错误:

无法将当前 JSON 对象(例如 {"name":"value"})反序列化为类型“system.Nullable[System.TimeSpan]”,因为该类型需要 JSON 原始值(例如字符串、数字、布尔值、null)正确反序列化。要修复此错误,要么将 JSON 更改为 JSON 原始值(例如字符串、数字、布尔值、null),要么将反序列化类型更改为正常的 .NET 类型(例如,不是像整数这样的原始类型,而不是可以从 JSON 对象反序列化的集合类型(如数组或列表)。 JsonObjectAttribute 也可以添加到类型中以强制它从 JSON 对象反序列化。Path 'InTime.Hours' line 1

重要的是要知道,我的服务器项目必须只使用 microsoft .net 序列化程序,而 win 应用程序必须只使用 Newtonesoft 反序列化程序!

毕竟我猜,如果是序列化器,make name:value 问题就解决了, 可能是这样的

{"EndTime":"090000"}

但我不知道如何强制序列化程序更改 TimeSpan 格式!

也许是这样的???? :-) :

public class Attendance
{
    public int ID { get; set; }
    public int PID { get; set; }

   [Define Format in serialization here (maybe !)]
    public System.TimeSpan time { get; set; }

}

【问题讨论】:

  • 我认为json格式可能是错误的..而不是.. "EndTime":{"Hours":9,"Minutes":0,"Seconds":0,"Milliseconds":0 ,"Ticks":324000000000,"Days":0,"TotalDays":0.375,"TotalHours":9,"TotalMilliseconds":32400000,"TotalMinutes":540,"TotalSeconds":32400} 不应该是... { "小时":9,"分钟":0,"秒":0,"毫秒":0,"滴答声":324000000000,"天":0,"TotalDays":0.375,"TotalHours":9,"TotalMilliseconds ":32400000,"TotalMinutes":540,"TotalSeconds":32400}
  • 我没有做到,它是由 ..net 框架标准的 Json 序列化程序制作的!

标签: json asp.net-mvc serialization json.net deserialization


【解决方案1】:

您的服务器使用JavaScriptSerializer 格式输出TimeSpan,而您的客户端期望Json.NET 格式的时间跨度。

通过测试可以看到两种格式,如下:

Debug.WriteLine(new JavaScriptSerializer().Serialize(DateTime.Today - DateTime.Today.AddDays(-1)))

哪个打印:

{"Ticks":864000000000,"Days":1,"Hours":0,"Milliseconds":0,"Minutes":0,"Seconds":0,"TotalDays":1,"TotalHours":24,"TotalMilliseconds":86400000,"TotalMinutes":1440,"TotalSeconds":86400}

对比

Debug.WriteLine(JsonConvert.SerializeObject(DateTime.Today - DateTime.Today.AddDays(-1)))

打印更简洁:

"1.00:00:00"

让 Json.NET 以 JavaScriptSerializer 格式解析 TimeSpan 对象非常容易,但您的要求正好相反:以 Json.NET 格式输出 JavaScriptSerializer。这更加困难,因为 Json.NET 将时间跨度表示为一个简单的字符串,但 JavaScriptConverter 只允许将类型映射到自定义 JSON 对象——而不是字符串。

因此,有必要将转换器应用于包含TimeSpan 的所有类型。这是一个通用转换器,它执行默认转换,然后覆盖所有TimeSpan-valued 属性和字段。它对于较小的类(例如您的示例类)将是高性能的,但对于序列化大型根类的性能较差,您可能需要为此编写自定义转换器:

public class TypeWithTimespanConverter<T> : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new[] { typeof(T) };
        }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        // Use a "fresh" JavaScriptSerializer here to avoid infinite recursion.
        var hasTimeSpan = (T)obj;

        // Generate a default serialization.  Is there an easier way to do this?
        var defaultSerializer = new JavaScriptSerializer();
        var dict = defaultSerializer.Deserialize<Dictionary<string, object>>(defaultSerializer.Serialize(obj));

        foreach (var pair in dict.ToList())
        {
            if (!(pair.Value is IDictionary))
                continue;
            TimeSpan span;
            if (obj.TryGetPropertyValueOfType<TimeSpan>(pair.Key, out span))
            {
                dict[pair.Key] = span.ToString();
                continue;
            }
            TimeSpan? spanPtr;
            if (obj.TryGetPropertyValueOfType<TimeSpan?>(pair.Key, out spanPtr))
            {
                if (spanPtr == null)
                    dict[pair.Key] = null;
                else
                    dict[pair.Key] = spanPtr.Value.ToString();
                continue;
            }
        }

        return dict;
    }
}

public static class ObjectExtensions
{
    public static bool TryGetPropertyValueOfType<T>(this object obj, string name, out T value)
    {
        if (obj == null)
            throw new NullReferenceException();
        var type = obj.GetType();
        var property = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
        if (property != null
            && property.GetIndexParameters().Length == 0
            && typeof(T).IsAssignableFrom(property.PropertyType)
            && property.GetGetMethod(false) != null)
        {
            value = (T)property.GetGetMethod(false).Invoke(obj, new object[0]);
            return true;
        }

        var field = type.GetField(name, BindingFlags.Public | BindingFlags.Instance);
        if (field != null
            && typeof(T).IsAssignableFrom(field.FieldType))
        {
            value = (T)field.GetValue(obj);
            return true;
        }

        value = default(T);
        return false;
    }
}

然后像这样使用它:

        var attendance = new Attendance { ID = 101, PID = -101, time = DateTime.Today - DateTime.Today.AddDays(-1).AddHours(-1) };

        var serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new JavaScriptConverter[] { new TypeWithTimespanConverter<Attendance>() });

        var json = serializer.Serialize(attendance);                        // Serialize with JavaScriptSerializer and TypeWithTimespanConverter
        Debug.WriteLine(json);                                              // Prints {"ID":101,"PID":-101,"time":"1.01:00:00"}
        var attendance2 = JsonConvert.DeserializeObject<Attendance>(json);  // Deserialize with Json.NET
        Debug.Assert(attendance2.time == attendance.time);                  // Assert that the timespan was converted

要在 ASP.NET 服务中配置转换器,请参阅How to: Configure ASP.NET Services in ASP.NET AJAX

【讨论】:

  • 你好,我使用 JavaScriptSerializer 反序列化没有任何问题,
  • @dr_traz - 澄清一下,您想将您的客户端从 Json.NET 切换到 JavaScriptSerializer?这是第二个问题,但请看这里:看这里:stackoverflow.com/questions/4383425/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-31
  • 2021-03-04
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2013-08-11
相关资源
最近更新 更多