DerrickBrayanClayton / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
0 stars 0 forks source link

Serialization of DateTimeOffset not culture invariant #47

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
Serialization of some CLR types seems to work just fine, like DateTime and
double - it is possible to serialize the values in one culture setting and
deserialize in another.

This however does not work with DateTimeOffset. Probably internally simply
ToString and Parse are used without using invariant culture settings or
instead of using the XmlConvert class.

Here is some test code demonstrating the problem:

            CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture;
            try
            {
                DateTimeOffset originalData = DateTime.Now;
                DateTimeOffset clonedData;

                #region serialization/deserialization roundtrip using
different cultures

                using (MemoryStream stream = new MemoryStream())
                {
                    // serialize with culture en-GB
                    Thread.CurrentThread.CurrentCulture = new
CultureInfo("en-GB");
                    Serializer.Serialize<DateTimeOffset>(stream, originalData);

                    // deserialize with culture de-DE (incompatible date
and number formats)
                    Thread.CurrentThread.CurrentCulture = new
CultureInfo("de-DE");
                    stream.Position = 0;
                    clonedData =
Serializer.Deserialize<DateTimeOffset>(stream); // <-- crashing here
                }

                #endregion

                // compare data
                Assert.AreEqual(originalData, clonedData);

Original issue reported on code.google.com by schmidt...@gmail.com on 3 Mar 2009 at 2:20

GoogleCodeExporter commented 8 years ago
I suspect that this is indeed picking the ToString/Parse pattern; I will see 
about 
changing the culture to invariant during serialization. Thanks for pointing 
this out.

Original comment by marc.gravell on 3 Mar 2009 at 5:11

GoogleCodeExporter commented 8 years ago
I reported this issue long time ago, and now, it bites me again...

I still had the mentioned ThreadCulture workaround in place, and I still had 
protobuf-net v1 running.

Now I have to switch to v2, and the built-in handling of DateTimeOffset has 
gone completely. (I checked the old code for any explicit handling of 
DateTimeOffset and didn't find anything, so I guess in v1 was some generic 
"ToString for everything I don't know" in place?) There would be enough options 
to handle this if I would start from scratch, however *my v2-based version 
still needs to be able to read files produced with v1*, and I can't get that to 
work.

When I use the v1-based version to output the .proto file, I get something like 
this:

---
message Foo {
   optional int32 bar = 1;
   optional string timeStamp = 2;
}
---

How can I keep this wire format? E. g. using a Surrogate doesn't work because 
it leads to an incompatible contract like this:

---
message DateTimeOffsetSurrogate {
   optional string legacyString = 1;
}
message Foo {
   optional int32 bar = 1;
   optional DateTimeOffsetSurrogate timeStamp = 2;
}
---

No matter what I tried, I always get "Invalid wire-type". Any idea, except 
adding a shim member for each and every DateTimeOffset property, which I really 
would prefer to avoid?

Original comment by schmidt...@gmail.com on 11 Jun 2013 at 11:37

GoogleCodeExporter commented 8 years ago
You can add `RuntimeTypeModel.Default.AllowParseableTypes = true;` (or very 
similar) which should enable this; it was causing conflicts in a few cases, so 
is not enabled by default in v2

Original comment by marc.gravell on 12 Jun 2013 at 6:33

GoogleCodeExporter commented 8 years ago
Marc, thank you very much, that actually helped! Commercial support couldn't be 
faster :)

And guess what: with AllowParseableTypes on, the old culture bug in back. So 
this ticket is still not fixed, I'm afraid. However, setting the current thread 
culture to InvariantCulture before calling into any serialization code still 
helps. 

Although calling ToString and Parse with InvariantCulture could  fix some of 
the "conflicts in a few cases" you mentioned, I agree that disabling this 
feature per default makes sense. E.g. when I started using it, I had no idea 
that there was no explicit handling of DateTimeOffset, and would have probably 
chosen an explicit typed conversation (e.g. by serializing the private members 
for the DateTime and the offset) to avoid the untyped string.

Original comment by schmidt...@gmail.com on 12 Jun 2013 at 1:00