2016-08-22 68 views
1

我一直在使用Protobuf-net作为使用服务堆栈通过HTTP进行通信的胖客户端应用程序的序列化程序。我们拥有大量音量的第一位客户在反序列化时开始出现错误。我们在某些模型中发送了DateTimeOffset类型,因此我们创建了一个将值作为字符串序列化的代理。从我们的日志中,我可以看到何时发生错误,这是它试图反序列化的日期值在时区偏移重复的末尾有一个额外的六个字符:Protobuf.net和序列化的DateTimeOffset

2016/8/9 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); 
     } 
    } 
} 

一旦发生此日期错误,它将不会正确序列化/反序列化,直到PC重新启动。我们无法以一种可以调试和查看剩余消息的方式重现此错误。这是有人熟悉的情况吗?我们使用的版本是2.0.0.640,由于这个问题,我更新到2.0.0.668,但问题依然存在。

+0

['DateTimeOffset.ToString()'](https://msdn.microsoft.com/en-us/library/bb360056(v = vs.110).aspx)使用**当前文化**,它可以机器不同。即在英国生成的协议缓冲区可能无法被美国的服务器解析。对于序列化,你应该使用不变的文化:['value.ToString(CultureInfo.InvariantCulture)'](https://msdn.microsoft.com/en-us/library/bb335841(v = vs.110).aspx)。并使用[等效方法](https://msdn.microsoft.com/en-us/library/bb356584(v = vs.110).aspx)进行解析。 – dbc

+0

当然,当前的文化设置可以由最终用户更改。例如,请参阅[这里](https://stackoverflow.com/questions/25251224/c-sharp-cultureinfo-currentculture-says-en-us-but-my-windows-settings-are-set-to)。 – dbc

+0

另请参阅[如何:往返日期和时间值:往返DateTimeOffset值](https://msdn.microsoft.com/zh-cn/library/bb882584(v = vs.110).aspx )。 – dbc

回答

1

看起来好像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 

也可能是客户端以某种方式修改了“很长一段时间:”字符串“区域和语言选项” - >“其他设置...”对话框,它看起来像(Windows 7)中:

enter image description here

如果客户这样做不知何故,和机器是一个域,该格式可以得到reset back on reboot这是你所看到的到底是什么。

可以手动执行此操作的客户端(虽然,从实验,试图追加K手动在Windows 7中的用户界面生成错误弹出,然后失败),或者可能有一些马车第三方应用做不知情你或他们通过致电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); 
     } 
    } 
} 

这不仅应该修复你所看到的错误,它还将确保你的应用程序在一个地区(比如说英国)生成的协议缓冲区可以在其他地方(比如美国)用其他日期和时间的文化格式进行解析。

+0

这真棒谢谢你! – Malaise