2016-08-22 51 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