Reputation: 3697
We are currently facing the problem that we want to port an application that is currently running on Android (Monodroid) and Wp7 to IOS by using MonoTouch.
That would be not the problem, but deserializing data by using the protobuf-net framework constantly fails with the following exception:
ProtoBuf.ProtoException: Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see http://stackoverflow.com/q/2152978/23354
at ProtoBuf.ProtoReader.StartSubItem (ProtoBuf.ProtoReader reader) [0x00000] in <filename unknown>:0
at ProtoBuf.BclHelpers.ReadGuid (ProtoBuf.ProtoReader source) [0x00000] in <filename unknown>:0
at TpSerializer.Read (Application.Mobile.TpDataAccess.TimeEntryLoggingDao.Entities.ActiveTimeEntryDbo , ProtoBuf.ProtoReader ) [0x00000] in <filename unknown>:0
at TpSerializer.Deserialize (Int32 , System.Object , ProtoBuf.ProtoReader ) [0x00000] in <filename unknown>:0
at ProtoBuf.Meta.TypeModel.TryDeserializeAuxiliaryType (ProtoBuf.ProtoReader reader, DataFormat format, Int32 tag, System.Type type, System.Object& value, Boolean skipOtherFields, Boolean asListItem, Boolean autoCreate, Boolean insideList) [0x00000] in <filename unknown>:0
at ProtoBuf.Meta.TypeModel.TryDeserializeList (ProtoBuf.Meta.TypeModel model, ProtoBuf.ProtoReader reader, DataFormat format, Int32 tag, System.Type listType, System.Type itemType, System.Object& value) [0x00000] in <filename unknown>:0
at ProtoBuf.Meta.TypeModel.TryDeserializeAuxiliaryType (ProtoBuf.ProtoReader reader, DataFormat format, Int32 tag, System.Type type, System.Object& value, Boolean skipOtherFields, Boolean asListItem, Boolean autoCreate, Boolean insideList) [0x00000] in <filename unknown>:0
at ProtoBuf.Meta.TypeModel.DeserializeCore (ProtoBuf.ProtoReader reader, System.Type type, System.Object value, Boolean noAutoCreate) [0x00000] in <filename unknown>:0
at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream source, System.Object value, System.Type type, ProtoBuf.SerializationContext context) [0x00000] in <filename unknown>:0
at ProtoBuf.Meta.TypeModel.Deserialize (System.IO.Stream source, System.Object value, System.Type type) [0x00000] in <filename unknown>:0
at Application.Mobile.TpDataAccess.Core.CoreProtobufDao`2[System.Guid,Application.Mobile.TpDataAccess.TimeEntryDao.Entities.TimeEntryDbo].EnsureCollection () [0x00000] in <filename unknown>:0
at Application.Mobile.TpDataAccess.TimeEntryDao.TimeEntryProtobufDao.PrepareAccess () [0x00000] in <filename unknown>:0
at Application.Mobile.TpBusinessComponents.TimeEntryService.TimeEntryService.PrepareAccess () [0x00000] in <filename unknown>:0
at App.TP.Mobile.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication app, MonoTouch.Foundation.NSDictionary options) [0x00031] in /Users/Developer/Dropbox/Application Mobile/Application Mobile iOS Project/Application_Mobile/AppDelegate.cs:34
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38
at App.TP.Mobile.Application.Main (System.String[] args) [0x00000] in /Users/Developer/Dropbox/Application Mobile/Application Mobile iOS Project/Application_Mobile/Main.cs:17
The thing is that we did not change the entities nor the way we are storing the data.
// and serialize
string file = Path.Combine(StoragePath, dataFileName);
using (var stm = new FileStream(file, FileMode.Create))
{
foreach (var item in list)
Serializer.Serialize(stm, item);
}
Doesn't matter which entity we read, it fails:
string file = Path.Combine(StoragePath, dataFileName);
if (!File.Exists(file))
return;
using (var stm = new FileStream(file, FileMode.Open))
{
var list = (TClass[]) Serializer.Deserialize(stm, null, typeof(TClass[]));
if (list == null)
return;
// transform array into dictionary
for (int i = 0; i < list.Length; i++)
{
var entity = list[i];
entities[primaryKeyFunction(entity)] = entity;
}
}
We are using the following Protobuf-NET environment.
Saving the data it's not the issue, but the loading fails. Any help is highly appreciated.
Thanks - Gerhard
Upvotes: 3
Views: 1339
Reputation: 1063338
A nice easy one. You have serialized as Foo
, and deserialized as Foo[]
. Actually, because protocol buffers is an appendable format, by using Serialize
repeatedly (to the same file), you are effectively only writing a single Foo
(but over-writing most of the members repeatedly).
Basically, to keep your current code, you could use SerializeWithLengthPrefix
in place of Serialize
, i.e.
foreach(var item in list)
{
Serializer.SerializeWithLengthPrefix(stm, item,
PrefixStyle.Base128, Serializer.ListItemTag);
}
but could also have simply used:
Serializer.Serialize(stm, list);
These are both semantically identical; in both cases what you get is (in a dense binary form):
[field 1, string]
[payload length of item 0]
[payload of item 0]
[field 1, string]
[payload length of item 1]
[payload of item 1]
...
[field 1, string]
[payload length of item n]
[payload of item n]
which is exactly what Deserialize
is looking for when you tell it TClass[]
Upvotes: 3