Protobuf.net 和 DateTimeOffset 的序列化
Protobuf.net and serialization of DateTimeOffset
我一直在使用 Protobuf-net 作为胖客户端应用程序的序列化程序,该应用程序使用服务堆栈通过 HTTP 进行通信。我们的第一个拥有大量数据的客户在反序列化时开始看到错误。我们在一些模型中发送 DateTimeOffset 类型,因此我们创建了一个将值序列化为字符串的代理项。从我们的日志中,我可以看到错误发生的时间,这是它试图反序列化的日期值,在重复时区偏移的末尾有一个额外的六个字符:
8/9/2016 12:02:37 AM-7:00 -7:00
这是我们代理人的代码。
[ProtoContract]
public class DateTimeOffsetSurrogate
{
[ProtoMember(1)]
public string DateTimeString { get; set; }
public static implicit operator DateTimeOffsetSurrogate(DateTimeOffset value)
{
return new DateTimeOffsetSurrogate { DateTimeString = value.ToString() };
}
public static implicit operator DateTimeOffset(DateTimeOffsetSurrogate value)
{
try
{
return DateTimeOffset.Parse(value.DateTimeString);
}
catch (Exception ex)
{
throw new Exception("Unable to parse date time value: " + value.DateTimeString, ex);
}
}
}
一旦发生此日期错误,它将无法正确 serialize/deserialize 直到 PC 重新启动。我们无法以允许我们调试和查看消息其余部分的方式重现此错误。这是有人熟悉的情况吗?我们使用的是 2.0.0.640 版本,由于这个问题,我更新到 2.0.0.668,但问题仍然存在。
看起来好像 CultureInfo.CurrentCulture.DateTimeFormat.LongTimePattern
在客户端的机器上不知何故变得混乱。我可以通过将 "K"
格式添加到 LongTimePattern
:
来重现该问题
var dateTime = DateTimeOffset.Parse(@"8/9/2016 12:02:37 AM-7:00");
var myCI = new CultureInfo("en-US");
myCI.DateTimeFormat.LongTimePattern = myCI.DateTimeFormat.LongTimePattern + " K";
Console.WriteLine(dateTime.ToString(myCI)); // Prints 8/9/2016 12:02:37 AM -07:00 -07:00
写入的字符串是8/9/2016 12:02:37 AM -07:00 -07:00
,这正是您所看到的。
可能是您的应用程序中存在错误,它在某处设置了 LongTimePattern
。我也可以重现这个问题:
Thread.CurrentThread.CurrentCulture = myCI;
Console.WriteLine(dateTime.ToString()); // Prints 8/9/2016 12:02:37 AM -07:00 -07:00
或者可能是客户端以某种方式修改了 "Region and Language" -> "Additional settings..." 对话框中的 "Long time:" 字符串,看起来像 (Windows 7):
如果客户端以某种方式执行此操作,并且计算机位于域中,则格式可能会 reset back on reboot 这正是您所看到的。
客户端可能手动执行此操作(尽管根据实验,尝试在 UI 中的 Windows 7 上手动附加 K
会生成错误弹出窗口然后失败),或者可能有一些有问题的第 3 方应用程序通过调用 SetLocaleInfo
.
在您或他们不知道的情况下执行此操作
您可以记录 LongTimePattern
的值以尝试跟踪问题,但无论如何您都应该修改 DateTimeOffsetSurrogate
以便它以文化不变的格式序列化 DateTimeOffset
, 最好由 How to: Round-trip Date and Time Values: To round-trip a DateTimeOffset value:
指定
[ProtoContract]
public class DateTimeOffsetSurrogate
{
[ProtoMember(1)]
public string DateTimeString { get; set; }
public static implicit operator DateTimeOffsetSurrogate(DateTimeOffset value)
{
return new DateTimeOffsetSurrogate { DateTimeString = value.ToString("o") };
}
public static implicit operator DateTimeOffset(DateTimeOffsetSurrogate value)
{
try
{
return DateTimeOffset.Parse(value.DateTimeString, null, DateTimeStyles.RoundtripKind);
}
catch (Exception ex)
{
throw new Exception("Unable to parse date time value: " + value.DateTimeString, ex);
}
}
}
这不仅可以修复您看到的错误,还可以确保您的应用程序在一个地区(例如英国)生成的协议缓冲区可以在其他地方(例如美国)以不同的文化格式进行解析日期和时间。
我一直在使用 Protobuf-net 作为胖客户端应用程序的序列化程序,该应用程序使用服务堆栈通过 HTTP 进行通信。我们的第一个拥有大量数据的客户在反序列化时开始看到错误。我们在一些模型中发送 DateTimeOffset 类型,因此我们创建了一个将值序列化为字符串的代理项。从我们的日志中,我可以看到错误发生的时间,这是它试图反序列化的日期值,在重复时区偏移的末尾有一个额外的六个字符:
8/9/2016 12:02:37 AM-7:00 -7:00
这是我们代理人的代码。
[ProtoContract]
public class DateTimeOffsetSurrogate
{
[ProtoMember(1)]
public string DateTimeString { get; set; }
public static implicit operator DateTimeOffsetSurrogate(DateTimeOffset value)
{
return new DateTimeOffsetSurrogate { DateTimeString = value.ToString() };
}
public static implicit operator DateTimeOffset(DateTimeOffsetSurrogate value)
{
try
{
return DateTimeOffset.Parse(value.DateTimeString);
}
catch (Exception ex)
{
throw new Exception("Unable to parse date time value: " + value.DateTimeString, ex);
}
}
}
一旦发生此日期错误,它将无法正确 serialize/deserialize 直到 PC 重新启动。我们无法以允许我们调试和查看消息其余部分的方式重现此错误。这是有人熟悉的情况吗?我们使用的是 2.0.0.640 版本,由于这个问题,我更新到 2.0.0.668,但问题仍然存在。
看起来好像 CultureInfo.CurrentCulture.DateTimeFormat.LongTimePattern
在客户端的机器上不知何故变得混乱。我可以通过将 "K"
格式添加到 LongTimePattern
:
var dateTime = DateTimeOffset.Parse(@"8/9/2016 12:02:37 AM-7:00");
var myCI = new CultureInfo("en-US");
myCI.DateTimeFormat.LongTimePattern = myCI.DateTimeFormat.LongTimePattern + " K";
Console.WriteLine(dateTime.ToString(myCI)); // Prints 8/9/2016 12:02:37 AM -07:00 -07:00
写入的字符串是8/9/2016 12:02:37 AM -07:00 -07:00
,这正是您所看到的。
可能是您的应用程序中存在错误,它在某处设置了 LongTimePattern
。我也可以重现这个问题:
Thread.CurrentThread.CurrentCulture = myCI;
Console.WriteLine(dateTime.ToString()); // Prints 8/9/2016 12:02:37 AM -07:00 -07:00
或者可能是客户端以某种方式修改了 "Region and Language" -> "Additional settings..." 对话框中的 "Long time:" 字符串,看起来像 (Windows 7):
如果客户端以某种方式执行此操作,并且计算机位于域中,则格式可能会 reset back on reboot 这正是您所看到的。
客户端可能手动执行此操作(尽管根据实验,尝试在 UI 中的 Windows 7 上手动附加 K
会生成错误弹出窗口然后失败),或者可能有一些有问题的第 3 方应用程序通过调用 SetLocaleInfo
.
您可以记录 LongTimePattern
的值以尝试跟踪问题,但无论如何您都应该修改 DateTimeOffsetSurrogate
以便它以文化不变的格式序列化 DateTimeOffset
, 最好由 How to: Round-trip Date and Time Values: To round-trip a DateTimeOffset value:
[ProtoContract]
public class DateTimeOffsetSurrogate
{
[ProtoMember(1)]
public string DateTimeString { get; set; }
public static implicit operator DateTimeOffsetSurrogate(DateTimeOffset value)
{
return new DateTimeOffsetSurrogate { DateTimeString = value.ToString("o") };
}
public static implicit operator DateTimeOffset(DateTimeOffsetSurrogate value)
{
try
{
return DateTimeOffset.Parse(value.DateTimeString, null, DateTimeStyles.RoundtripKind);
}
catch (Exception ex)
{
throw new Exception("Unable to parse date time value: " + value.DateTimeString, ex);
}
}
}
这不仅可以修复您看到的错误,还可以确保您的应用程序在一个地区(例如英国)生成的协议缓冲区可以在其他地方(例如美国)以不同的文化格式进行解析日期和时间。