Fast Serialization exception

Posts   
 
    
mikeg22
User
Posts: 411
Joined: 30-Jun-2005
# Posted on: 22-Aug-2007 00:45:10   

Version 2.5, Adapter

I am trying to serialize a simple, empty EntityCollection(of FolderRelation) and I get this exception on Deserialization:


   System.ThrowHelper.ThrowArgumentOutOfRangeException(argument As ExceptionArgument, resource As ExceptionResource)
       CODA GUI.EXE: N 00062
   System.ThrowHelper.ThrowArgumentOutOfRangeException()
       CODA GUI.EXE: N 00012
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadTokenizedString(bucket As Int32)
       CODA GUI.EXE: N 00064
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadOptimizedString()
       CODA GUI.EXE: N 00027
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.ReadEntityMemberCollections(entity As EntityBase2)
       CODA GUI.EXE: N 00159
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.ReadReferencedEntities(rootEntity As EntityBase2)
       CODA GUI.EXE: N 00447
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.Deserialize(collection As IFastSerializableEntityCollection2)
       CODA GUI.EXE: N 00052
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.Deserialize(serializedData As Byte[], root As Object)
       CODA GUI.EXE: N 00105
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationHelper.Deserialize(entityCollection As IEntityCollection2, info As SerializationInfo, context As StreamingContext)
       CODA GUI.EXE: N 00039
   SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase2`1..ctor(info As SerializationInfo, context As StreamingContext)
       CODA GUI.EXE: N 00191
   Coda.Entities.HelperClasses.EntityCollection`1..ctor(info As SerializationInfo, context As StreamingContext)
       EntityCollection.vb: line 0116, col 04, IL 0001

What is really strange is the FastDeserializer.ReadEntityMemberCollections is running at all, as there were no entities in the collection to begin with.

EDIT: I realized this was not an empty collection. It was a collection that had been fetched from the database, and is deserializing while remoting back to the client machine.

The prefetch path that fetches this collection is:


Dim prefetchPath As IPrefetchPath2 = New PrefetchPath2(CInt(EntityType.FolderRelationEntity))
Dim foldersElement As IPrefetchPathElement2 = prefetchPath.Add(FolderRelationEntity.PrefetchPathFolder)

FolderRelation has a M:1 relationship with Folder. So FolderRelation (M:1) Folder

When I remove the PrefetchPathElement that goes to 'Folder' there is no problem with the serialization.

mikeg22
User
Posts: 411
Joined: 30-Jun-2005
# Posted on: 22-Aug-2007 03:35:06   

I've retested the fast serialization with all kinds of different object graphs (Entity based and EntityCollection based), and they all give errors on the Deserialization. The exceptions are usually "InvalidCastException."

I don't know what I could be doing wrong here. I have identical DLLs on the client and server side, use Binary formatting, have set the SerializationHelper.Optimization = Fast on both sides, and am not doing any serialization of custom properties.

Here's what happens when I try to fetch a single entity with a 1:N relationship in its prefetchpath across a remoting boundary (using binary formatting):

TargetInvocationException: {"Unable to read beyond the end of the stream."}


at System.RuntimeMethodHandle._SerializationInvoke(Object target, SignatureStruct& declaringTypeSig, SerializationInfo info, StreamingContext context)
   at System.RuntimeMethodHandle.SerializationInvoke(Object target, SignatureStruct declaringTypeSig, SerializationInfo info, StreamingContext context)
   at System.Reflection.RuntimeConstructorInfo.SerializationInvoke(Object target, SerializationInfo info, StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object obj, SerializationInfo info, StreamingContext context)
   at System.Runtime.Serialization.ObjectManager.FixupSpecialObject(ObjectHolder holder)
   at System.Runtime.Serialization.ObjectManager.DoFixups()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Remoting.Channels.CoreChannel.DeserializeBinaryResponseMessage(Stream inputStream, IMethodCallMessage reqMsg, Boolean bStrictBinding)
   at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at CODA.DataAccessGateway.DataAccessGateway.FetchEntity(IEntity2& entity, PrefetchPath2 prefetchPath)
   at Coda.BusinessServicesProviders.EntityManagers.EntityManagerBase.FetchEntity(CommonEntityBase& entity, PrefetchPath2 prefetchPath) in C:\Projects\CODA\41\Source\BusinessServicesProviders\EntityManagers\EntityManagerBase.vb:line 41

This happens whether or not I use a normal BinaryFormatter to do the Serialize/Deserialize or use the remoting system...

Here's some code:


Dim myEntity as New EmployeeEntity("0885")
myEntity.EmployeeBonus.AddNew
Dim formatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim stream As New System.IO.MemoryStream
formatter.Serialize(stream, myEntity)
stream.Position = 0
Dim myobject As Object = formatter.Deserialize(stream)

BLAM! System.IO.EndOfStreamException


SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadOptimizedInt32()
       CODA GUI.EXE: N 00016
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadTokenizedString(bucket As Int32)
       CODA GUI.EXE: N 00013
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadOptimizedString()
       CODA GUI.EXE: N 00027
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.ReadEntityMemberCollections(entity As EntityBase2)
       CODA GUI.EXE: N 00159
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.ReadReferencedEntities(rootEntity As EntityBase2)
       CODA GUI.EXE: N 00447
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.Deserialize(entity As EntityBase2)
       CODA GUI.EXE: N 00044
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.Deserialize(serializedData As Byte[], root As Object)
       CODA GUI.EXE: N 00148
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationHelper.Deserialize(entity As EntityBase2, info As SerializationInfo, context As StreamingContext)
       CODA GUI.EXE: N 00039
   SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2..ctor(info As SerializationInfo, context As StreamingContext)
       CODA GUI.EXE: N 01180
   Coda.Entities.EntityClasses.CommonEntityBase..ctor(info As SerializationInfo, context As StreamingContext)
       CommonEntityBase.vb: line 0054, col 04, IL 0001
   Coda.Entities.EntityClasses.EmployeeEntity..ctor(info As SerializationInfo, context As StreamingContext)
       EmployeeEntity.vb: line 0283, col 04, IL 0001


Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 22-Aug-2007 09:52:39   
Dim myEntity as New EmployeeEntity("0885")
myEntity.EmployeeBonus.AddNew
Dim formatter As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
Dim stream As New System.IO.MemoryStream
formatter.Serialize(stream, myEntity)
stream.Position = 0
Dim myobject As Object = formatter.Deserialize(stream)

And if you seek back to the beginning of the stream? Example:


[Test]
public void SerializationWithMNRelationFastTest()
{
    EntityCollection<CustomerEntity> customers = new EntityCollection<CustomerEntity>();
    PrefetchPath2 path = new PrefetchPath2(EntityType.CustomerEntity);
    path.Add(CustomerEntity.PrefetchPathEmployees);
    using(DataAccessAdapter adapter = new DataAccessAdapter())
    {
        adapter.FetchEntityCollection(customers, new RelationPredicateBucket(CustomerFields.Country == "Germany"), path);
    }
    Assert.AreEqual(11, customers.Count);
    foreach(CustomerEntity customer in customers)
    {
        Assert.IsTrue(customer.Employees.Count > 0);
    }

    SerializationHelper.Optimization = SerializationOptimization.Fast;
    BinaryFormatter formatter = new BinaryFormatter();
    MemoryStream stream = new MemoryStream();
    formatter.Serialize(stream, customers);

    stream.Seek(0, SeekOrigin.Begin);  // <<<<<<<<<<<<<<<<<<<<<

    EntityCollection<CustomerEntity> deserializedCustomers = (EntityCollection<CustomerEntity>)formatter.Deserialize(stream);
    Assert.AreEqual(11, deserializedCustomers.Count);
    foreach(CustomerEntity customer in deserializedCustomers)
    {
        Assert.IsTrue(customer.Employees.Count > 0);
    }
}

which succeeds...

Have you set any objectid settings, have you added a custom packer to the serializer?

Frans Bouma | Lead developer LLBLGen Pro
mikeg22
User
Posts: 411
Joined: 30-Jun-2005
# Posted on: 22-Aug-2007 15:39:05   

I replaced my

stream.Position =0

with

stream.Seek(0, SeekOrigin.Begin)

and I get an identical exception with the same stack trace:

SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadOptimizedInt32()
       CODA GUI.EXE: N 00016
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadTokenizedString(bucket As Int32)
       CODA GUI.EXE: N 00013
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationReader.ReadOptimizedString()
       CODA GUI.EXE: N 00027
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.ReadEntityMemberCollections(entity As EntityBase2)
       CODA GUI.EXE: N 00160
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.ReadReferencedEntities(rootEntity As EntityBase2)
       CODA GUI.EXE: N 00447
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.Deserialize(entity As EntityBase2)
       CODA GUI.EXE: N 00044
   SD.LLBLGen.Pro.ORMSupportClasses.FastDeserializer.Deserialize(serializedData As Byte[], root As Object)
       CODA GUI.EXE: N 00148
   SD.LLBLGen.Pro.ORMSupportClasses.SerializationHelper.Deserialize(entity As EntityBase2, info As SerializationInfo, context As StreamingContext)
       CODA GUI.EXE: N 00039
   SD.LLBLGen.Pro.ORMSupportClasses.EntityBase2..ctor(info As SerializationInfo, context As StreamingContext)
       CODA GUI.EXE: N 01180
   Coda.Entities.EntityClasses.CommonEntityBase..ctor(info As SerializationInfo, context As StreamingContext)
       CommonEntityBase.vb: line 0054, col 04, IL 0001
   Coda.Entities.EntityClasses.EmployeeEntity..ctor(info As SerializationInfo, context As StreamingContext)
       EmployeeEntity.vb: line 0283, col 04, IL 0001


I'm not sure what you mean by "ObjectId settings." I don't think I'm doing anything special to the entity's hash codes or anything. I have not added a custom packer to the serializer.

I've sent a sql script to make the tables these entities are based off to support[AT]llblgen.com...hopefully it is just a datatype that I'm using disappointed

mikeg22
User
Posts: 411
Joined: 30-Jun-2005
# Posted on: 22-Aug-2007 17:43:20   

I've built a fresh solution with no custom code using those two entities only, and I don't have the same problem. It may have something to do with what happens in my custom overriden code in EntityCollection, or possibly with the specific relations set up one of the entities...still looking disappointed

EDIT: I'm wrong, when I set the Optimization = Fast, I get the same problem.

Same exception and everything.

To recap, this a fresh, out of the box adapter project with EmployeeEntity and EmployeeBonusEntity, and a few more relations. So, it looks like it is the extra entities (with relations to EmployeeEntity) that are causing the problem...I'll keep looking.

EDIT:

I've sent the solution+projects where this problem is demonstrated to your support email.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 22-Aug-2007 18:26:45   

I've received your code + .rar file. I'll check it out.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39910
Joined: 17-Aug-2003
# Posted on: 23-Aug-2007 12:01:56   

This issue appeared to be VB.NET and template related. Code ported from C# to VB.NET wasn't done properly, the VB.NET code had an incorrect CreateMemberEntityCollectionsQueue routine in entityIncludeAdapter.template. To fix it locally now, you have to add: Else toAdd = Nothing

to the two If statements in the routine. simple_smile We'll release the public fix soon.

Frans Bouma | Lead developer LLBLGen Pro