StrataFrame Forum

Serialization

http://forum.strataframe.net/Topic182.aspx

By John Frankewicz - 11/29/2005

Our application requires that fields in the database, represented by the business object, be serialized remotely.

Could someone explain the process or point me to a link that explains how this process is done in your framework?

1. Do you have an option where the  serialized data is  stored?

2. Can it be hooked into the .net remoting?

3. How do you select what is serialized? I thought it was done after the object is dropped on the form?

By Trent L. Taylor - 11/29/2005

There are two serialization methods on a business object: SerializeToStream and SerialzieToByteArray. These work just as the names state. SerializeToStream supports any stream type such as a network stream, file stream, memory stream, etc. Here is a sample of serializing a business object and then de-serializing it. I am using a file stream here for sample purposes, but you could just as easily use a network stream which could be remoted or allow you to create a server that hands out business objects. The possibilities are limitless.



Serialize the Business Object

Private Sub SerializeMethod()

'-- Establish Locals

Dim loFile As New System.IO.FileStream("c:\serializedBO.bin", System.IO.FileMode.Create)

Dim loCustomers As New CustomersBO()




'-- Load some data into the business object

loCustomers.FillAll()




'-- Serialize the business object to the stream

loCustomers.SerializeToStream(loFile)




'-- Close the stream

loFile.Close()




'-- Close the BO

loCustomers.Dispose()

End Sub




De-serialize the Business Object

Private Sub DeserializeMethod()

'-- Establish Lcoals

Dim loFile As New System.IO.FileStream("c:\serializedBO.bin", System.IO.FileMode.Open)

Dim loCustomers As CustomersBO




'-- Deserialize the saved business object from a stream

loCustomers = CustomersBO.DeserializeBusinessObject(loFile)




'-- Close the stream

loFile.Close()

End Sub
By Edhy Rijo - 3/11/2009

Hi Trent,

I am trying to use the BO.SerializeToStream and DeserializeBusinessObject based on the error in the previous post, but I am hitting an error.  Here is the version of the code I am using:

Private Sub SerializeMethod()

     '-- Establish Locals

     Dim memString As New System.IO.MemoryStream

     Dim loCustomers As New CustomersBO()

     '-- Load some data into the business object

     loCustomers.FillAll()

     '-- Serialize the business object to the stream

     loCustomers.SerializeToStream(memString)

     '-- Close the stream

     memString.Close()

     '-- Close the BO

     loCustomers.Dispose()

     Me.DeserializeMethod(memString)

End Sub

'De-serialize the Business Object

Private Sub DeserializeMethod(ByVal memString As System.IO.MemoryStream)

     '-- Establish Lcoals

     Dim loCustomers1 As New CustomersBO

     '-- Deserialize the saved business object from a stream

     loCustomers1 = CustomersBO.DeserializeBusinessObject(memString)

End Sub

Here is the stack error:

ArgumentException
  Stream was not readable.

Source     : mscorlib

Stack Trace:
   at System.IO.BinaryReader..ctor(Stream input, Encoding encoding)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser..ctor(Stream stream, ObjectReader objectReader)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, IMethodCallMessage methodCallMessage)
   at MicroFour.StrataFrame.Business.BusinessLayer.DeserializeBusinessObject(Stream InputStream)
   at CollisionTest.testForm.DeserializeMethod(MemoryStream memString) in E:\Visual Studio 2008 Projects\StrataFrame\Samples\AutoCompleteTest\AutoCompleteTest\TestForm.vb:line 41
   at CollisionTest.testForm.SerializeMethod() in E:\Visual Studio 2008 Projects\StrataFrame\Samples\AutoCompleteTest\AutoCompleteTest\TestForm.vb:line 31
   at CollisionTest.testForm.Button1_Click(Object sender, EventArgs e) in E:\Visual Studio 2008 Projects\StrataFrame\Samples\AutoCompleteTest\AutoCompleteTest\TestForm.vb:line 11
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativewindow.WndProc(Message& m)
   at System.Windows.Forms.Nativewindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Testing with System.IO.FileStream works just fine, what do I need to make it work with a System.IO.MemoryStream?

By Edhy Rijo - 3/11/2009

Edhy Rijo (03/11/2009)
I am trying to use the BO.SerializeToStream and DeserializeBusinessObject based on the error in the previous post, but I am hitting an error.  Here is the version of the code I am using:

Sorry, the highlighted phrase should have said: based on the code...

By Trent L. Taylor - 3/12/2009

You are welcome to post a sample reproducing the error, because I just tested this and it works fine.  So there must be something else going on within your environment.  I just did this and it worked:

Dim mem As New System.IO.MemoryStream()
Me.CustomerBO1.SerializeToStream(mem)

By Edhy Rijo - 3/12/2009

Hi Trent,

The problem is with DeserializeBusinessObject. In your test did you try loCustomers1 = CustomersBO.DeserializeBusinessObject(memString)

'De-serialize the Business Object

Private Sub DeserializeMethod(ByVal memString As System.IO.MemoryStream)

     '-- Establish Lcoals

     Dim loCustomers1 As New CustomersBO

     '-- Deserialize the saved business object from a stream

     loCustomers1 = CustomersBO.DeserializeBusinessObject(memString)

End Sub

I can not post a sample right now because I am not in the office, but I would appreciate if you can try deserializing the memory stream.

Thanks!

By Trent L. Taylor - 3/12/2009

Yup, it worked.  You have to reposition the stream back to the 0 position, but it works like it should.

Dim mem As New System.IO.MemoryStream()
Me.CustomerBO1.SerializeToStream(mem)
mem.Seek(0, IO.SeekOrigin.Begin)
Dim desObj As CustomerBO = MicroFour.StrataFrame.Business.BusinessLayer.DeserializeBusinessObject(mem)

By Edhy Rijo - 3/12/2009

Trent L. Taylor (03/12/2009)
Yup, it worked.  You have to reposition the stream back to the 0 position, but it works like it should.

Trent, thanks a lot for testing this, the missing part was the code to reposition the stream back to the 0 position.

Dim mem As New System.IO.MemoryStream()
Me.CustomerBO1.SerializeToStream(mem)
mem.Seek(0, IO.SeekOrigin.Begin)
Dim desObj As CustomerBO = MicroFour.StrataFrame.Business.BusinessLayer.DeserializeBusinessObject(mem)

Since this my first time working with a MemoryStream, I wonder, should the BO.DeserializeBusinessObject(mem) method take care of repositioning the passed stream to the 0 position?

By Trent L. Taylor - 3/12/2009

Since this my first time working with a MemoryStream, I wonder, should the BO.DeserializeBusinessObject(mem) method take care of repositioning the passed stream to the 0 position?

No.  This could cause all types of issues.  This is the responsibility of the developer.  The same issue would come up with a file.  Most of the time you are not trying to do all of this within the same segment of code, the difference here is that you wrote to it then turned right around and read from it...so in this instance you have to reset the pointer.

By Edhy Rijo - 3/13/2009

Trent,

Another question about serialization, when we use this command:

pszOutMemByte = Me.bizConnectedClients1.SerializeToByteArray()

Is there a way to add some extra data to the pszOutMemByte variable?  With my communication library, I need to add and End Of Line character to the byte stream and have not found a way to do this, so the communication event will trigger when all data have arrive, so the question is how do I add these character to this byte array pszOutMemByte?

By Trent L. Taylor - 3/14/2009

Sure.  If I were going to do this I would put it in the front of the byte array with any information that will tell me where the serialized BO starts, etc.  So the beginning of the byte array would be a "header" that contained whatever information that you needed.  This is why I mentioned that resetting the memory stream was not a safe thing to do as other people may be using the memory stream for other things.
By Edhy Rijo - 3/14/2009

Trent L. Taylor (03/14/2009)
Sure. If I were going to do this I would put it in the front of the byte array with any information that will tell me where the serialized BO starts, etc. So the beginning of the byte array would be a "header" that contained whatever information that you needed. This is why I mentioned that resetting the memory stream was not a safe thing to do as other people may be using the memory stream for other things.


Yes, but can you give me a sample code of how to add the info to the byte array? in my case I will enter the code at the end of the array and the communication library will take care of removing it from the transferred stream.
By Trent L. Taylor - 3/15/2009

Hmmm....it is going to be a lot mroe difficult to add it at the end as you will not know the length of the serialized BO.  That is why a header would work much better as you would know what to expect that tells you what is further down the stream.
By Edhy Rijo - 3/15/2009

Trent L. Taylor (03/15/2009)
Hmmm....it is going to be a lot mroe difficult to add it at the end as you will not know the length of the serialized BO.  That is why a header would work much better as you would know what to expect that tells you what is further down the stream.

Hi again,

Thanks, but could you provide a quick sample code on how to add this byte to the header?  sorry, but I am really lost here w00t

By Trent L. Taylor - 3/16/2009

Well, it would just be a matter of creating your header in a string format, etc.  Then place that header at the beginning.  For example, I might have an enum that tells me the contents of the byte array in the first element.  In this case, a "1" would indicate a business object.  You could make this as long as you need since you would be in control of the header.  The second part of the header may indicate, in bytes, the length of the serialized BO.

Dim header As String = "1|"
Dim bo() As Byte
Dim mem As New System.IO.MemoryStream()
Dim headerInBytes() As Byte

'-- Serialize the BO to a byte array
bo = MyBO.SerializeToByteArray()

'-- Create the header
header &= bo.Length.ToString()

'-- Place an ending tag on the header
header &= "|"

headerInBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(header)

'-- Create the full byte array
mem.Write(headerInBytes, 0, headerinBytes.Length)

'-- Add the BO to the byte array
mem.Write(bo, 0, bo.Length)

'-- Convert the stream into a byte array
mem.Seek(0, Begin)
Dim r() As Byte = mem.ToArray()

So when you get the byte array on the server side (or whereever) you already know what to expect in the header.  So you can parse it out of the array (convert it back into a string or whatever you expect) and then you know what to do with the rest of the array.

By Edhy Rijo - 3/16/2009

Thanks a lot Trent, that will get me started.