locked
Binary stream '0' does not contain a valid BinaryHeader Exception RRS feed

  • Question

  • The full Exception with VS2005 is:

    Binary stream '0' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization."

     

    // This is the main DLL file.

    using namespace System::String

    using namespace System::IO

     

    #include "stdafx.h"

    #include "cppdll.h"

    #using <System.dll>

    #using <System.Windows.Forms.dll>

     

    using namespace System;

    using namespace System::IO;

    using namespace System::Text;

    using namespace System::Collections;

    using namespace System::Windows::Forms;

    using namespace System::ComponentModel;

    using namespace System::Runtime::Serialization;

    using namespace System::Runtime::Serialization::Formatters::Binary;

     

    public ref class DA      

    {

          protected:

        [Serializable]

          ref struct SrvrDes

       {

         String^DsplyName;

           bool ^ Administrated;

           String^ FES; // Full Encrypted String

           String^ UsrPortion;

           String^ AlwaysPortion;

       };

       ArrayList^ AL;

    private:

         

          SrvrDes^ SD;

          FileStream^ fsi;

     

    public: DA()  // Class Contructor

            {

                  AL = gcnew ArrayList; 

                  BinaryFormatter^ binformatter = gcnew BinaryFormatter;

                  Object^ obj = gcnew Object;

                  fsi = gcnew FileStream(String::Concat( Application::UserAppDataPath, "\\data.dbs" ) , FileMode::OpenOrCreate);

                  try

                  {

                     AL = dynamic_cast<ArrayList^>(binformatter ->Deserialize(fsi)); <EXCEPTION

                  }

                  catch ( SerializationException^ e )

                  {

                        AL->Clear();

                  }

                  fsi->Close();

            }              

     

          public: bool WD(String^ ID ) // Write Data

    {

          FileStream^ fso;

          SD = gcnew SrvrDes;

          SD->DsplyName = ID;

          SD->Administrated = false;

          SD->AlwaysPortion = "";

          SD->FES = "";

          SD->UsrPortion="";

          AL->Add(SD);

         

        fso = gcnew FileStream(String::Concat( Application::UserAppDataPath, "\\data.dbs" ) , FileMode::Open);

          BinaryFormatter^ formatter = gcnew BinaryFormatter;

          try

          {

             formatter->Serialize( fso, AL );

          }

          catch ( SerializationException^ e )

          {

           return false;

          }

          finally

          {

             fso->Close();

          }

     

          return true;

    }

     

          public: String^ RD(int index) // Read Data

    {

          SD = dynamic_cast<SrvrDes^>(AL[index]);

          return SD->DsplyName;

    }                

       };

         

    There is a calling test program:

     

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    Dim a As New DA

    Dim b As Boolean = a.WD("Hello World")

    Dim c As String = a.RD(0)

    End Sub

    The test program instantiates the class in the DLL which should create the file if it's not there or read it if it is there. Then it writes a serialized struct to the file.

    Dumps of the file show that the serialized data is there and that the header is intact and not corrupted,

    Exiting the program and restarting it cause the exception in the constructor. Exceptions occur with a newly rebuilt assembly.

    Stack Dump is as follows:

     at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
       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.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
       at DA..ctor() in g:\avb2005\cppdll\cppdll.cpp:line 46"

    There is no network drives and this is not a share. OS is XP Pro SP2 with all current patches.

    What the exception is saying is that it cannot read the serialization header and I don't know why.

     

    Friday, September 15, 2006 7:50 PM

Answers

  • This is a known issue with the BinaryFormatter. Can you please consider changing SrvrDes.Administrated from bool^ to bool? Was it meant to be a reference (boxed) type?

    Thanks

    Wednesday, September 27, 2006 6:46 AM
    Moderator

All replies

  • Hi,

    I'm having trouble using the BinaryFormatter class. When I call Deserialize (see below for code sample), I get this exception:

    System.Runtime.Serialization.SerializationException: Binary stream '0' does not contain a valid BinaryHeader. Possible causes are invalid stream or object version change between serialization and deserialization.


        Public Overrides Sub WriteXml(ByVal writer As System.Xml.XmlWriter)
            writer.WriteStartElement(XmlConstants.NamespaceQualifier, XmlConstants.ObjectElementName, XmlConstants.XmlNamespace)
           
            If m_Formatter Is Nothing Then
                m_Formatter = New BinaryFormatter()
            End If

            Dim ms As New MemoryStream()
            m_Formatter.Serialize(ms, Me.Data)

            Dim bytes(CInt(ms.Length)) As Byte
            ms.Read(bytes, 0, CInt(ms.Length))
            ms.Close()

            writer.WriteCData(Convert.ToBase64String(bytes))

            writer.WriteEndElement()
            writer.Flush()
        End Sub

        Public Overrides Sub ReadXml(ByVal navigator As XPathNavigator)
            navigator.MoveToChild(XmlConstants.ObjectElementName, XmlConstants.XmlNamespace)

            If m_Formatter Is Nothing Then
                m_Formatter = New BinaryFormatter
            End If

            Dim bytes() As Byte
            bytes = Convert.FromBase64String(navigator.Value)

            Dim ms As New MemoryStream()
            ms.Write(bytes, 0, bytes.Length)
            ms.Flush()
            ms.Position = 0

            Me.Data = m_Formatter.Deserialize(ms) '**** This is where the exception occurs
        End Sub

     


    What have I done wrong?

    Thanks in advance!
    Monday, December 5, 2005 6:15 AM
  •  

     I code the identical logic in VB and it works.

    Imports System

    Imports System.IO

    Imports System.Text

    Imports System.Collections

    Imports System.ComponentModel

    Imports System.Runtime.Serialization

    Imports System.Windows.Forms

    Imports System.Runtime.Serialization.Formatters.Binary

     

    Public Class SData

     

        <Serializable()> Protected Structure SrvrDes

            Public DsplyName As String

            Public Administrated As Boolean

            Dim FES As String ' Full Encrypted String

            Dim UsrPortion As String

            Dim AlwaysPortion As String

        End Structure

     

        Private AL As ArrayList

     

        Public Sub New()

     

     

            Dim fsi As FileStream = Nothing

            AL = New ArrayList

            Dim obj As Object

            Dim sc As StreamingContext = New StreamingContext(StreamingContextStates.File Or StreamingContextStates.Persistence)

            Dim binformatter As New BinaryFormatter

            Try

                fsi = New FileStream(Application.UserAppDataPath + "\\data.dbs", FileMode.OpenOrCreate)

                obj = binformatter.Deserialize(fsi)

                AL = DirectCast(obj, ArrayList)

            Catch e As SerializationException

                AL.Clear()

            End Try

     

            fsi.Close()

        End Sub

        Public Function WDd(ByVal ID As String) ' Write Data

     

            Dim fso As FileStream

            Dim SD As New SrvrDes

            SD.DsplyName = ID

            SD.Administrated = False

            SD.AlwaysPortion = ""

            SD.FES = ""

            SD.UsrPortion = ""

            AL.Add(SD)

     

            fso = New FileStream(Application.UserAppDataPath + "\\data.dbs", FileMode.OpenOrCreate)

            Dim formatter As BinaryFormatter = New BinaryFormatter

            Try

     

                formatter.Serialize(fso, AL)

     

            Catch e As SerializationException

     

                Return False

     

            Finally

     

                fso.Close()

            End Try

     

            Return True

        End Function

     

    End Class

     

    Note: I safecasted the assignment of the boolean to false in the struct. That made no difference.

    Saturday, September 16, 2006 8:26 PM
  • The first byte of a BinaryFormatter steam is a value that enumerates the type of the object that is stored. The BinaryFormatter will throw an exception if it finds a byte it doesn't recognize.  The '0' is the value it found.

    That's what... Why? I can't be sure, but I see you're deserializing in DA's constructor (Sub New in VB).  In your Form1_Load you create a new DA first (calling it's constructor and attempting to load the contents of data.dbs). I don't see anywhere where you create the data.dbs file before you do that.  If data.dbs doesn't contain valid data you'll get the exception you're seeing.

    Sunday, September 17, 2006 2:44 AM
    Moderator
  •  

    Thank you for looking at this, Peter.

    The constructor reads the file with an Open or create. If the File isn't there, it's created by the constructor.

    If there if no data there, the binary formatter will generate an "Attempting to deserailize stream with no data" exception and that's handled.

    The test program then instantiates a structure and fills in a field and serializes it. All of this seemed to work in the C++ dll. It created the file and also had the first exception. It then serialized the data.

    Using search in this forum, I found a reference to the internals of a serialized file which documented all the expected data in a serialized file. The C++ dll and VB test program seemed to appropriately fill in the header and the serialized data very nicely.

    With the C++ dll, stopping the program and restarting should read deserialize the data, filling in the arraylist with a list of the serialized structures. It's the arraylist that's being serialized and deserialized.

    Please understand that I am anything but a c++ guru. I took the C++ code and translated it into a VB dll line for line and it works exactly as expected.

    I really don't understand what is going wrong in the c++ dll. It's a little bit of a moot point. I was hoping that a c++ dll would use native mode code. It doesn't when you are calling clr classes. The c++ dll is everybit as interpretable by reflector as any vb code. So there is no gain for me in using a c++ dll. But I'd still really like to know why the c++ code failed.

    Renee

     

     

    Sunday, September 17, 2006 5:41 AM
  • It's has to tell.  I assume DA::WD doesn't encounter any SerializationException.  When you ran the VB version,  I assume that was after the VC version and the data.dbs file existed?

    You CLI/C++ isn't identical to the VB.  For example, the Administered member on SrvrDes is a reference to a value, where you VB it's just a value.  But, I don't think that particular difference would cause what you're seeing.  I'd have to look more closely to see if there were any other differences.

    In terms of native, anything that accesses any managed classes will be managed, not native.  But, you can push all your value-added logic to unmanaged classes to "hide" them in native code.  Makes it hard to take advantage of .NET like that though.

    Monday, September 18, 2006 8:44 PM
    Moderator
  •  

    Peter,

    All of your questions were wise question but I'm afraid I was very meticulous in the testing. After each test, I deleted the created file. So the VB DLL created it's own file.

    After running a test I inspected the file contents and they looked normal and I could see the data "Hello World" in both the C++ DLL and the VB DLL.

    "It's has to tell.  I assume DA::WD doesn't encounter any SerializationException."

    None at all they both ran very cleanly and both put data in the file with what looked to be a valid serialization header.

    No, DA:WD did not encounter and y exceptions. Instantiation followed by DA:WD produced created a file.

      When you ran the VB version,  I assume that was after the VC version and the data.dbs file existed?

    No. I cleaned up after each test.

     

    You CLI/C++ isn't identical to the VB.  For example, the Administered member on SrvrDes is a reference to a value, where you VB it's just a value.  But, I don't think that particular difference would cause what you're seeing.  I'd have to look more closely to see if there were any other differences.

    It didn't as they both wrote the data.

    In terms of native, anything that accesses any managed classes will be managed, not native.  But, you can push all your value-added logic to unmanaged classes to "hide" them in native code.  Makes it hard to take advantage of .NET like that though.

    I have to blush here. There was lots of logic. But it was in things that were heavily clr dependent such as triple-des encryption etc. My value added was simply architeture, execution flow and what to do. There isn't much reason to do a C++ dll, just to obscure things.

     


    Tuesday, September 19, 2006 3:06 AM
  •  

    Peter,

    Here is a hex dump of the C++ DLL serialized file created by the C++ dll

    I'll get the VB File next - I've never done side by side comparisons

    00000000  00 01 00 00 00 FF FF FF-FF 01 00 00 00 00 00 00  ................
    00000010  00 04 01 00 00 00 1C 53-79 73 74 65 6D 2E 43 6F  .......System.Co
    00000020  6C 6C 65 63 74 69 6F 6E-73 2E 41 72 72 61 79 4C  llections.ArrayL
    00000030  69 73 74 03 00 00 00 06-5F 69 74 65 6D 73 05 5F  ist....._items._
    00000040  73 69 7A 65 08 5F 76 65-72 73 69 6F 6E 05 00 00  size._version...
    00000050  08 08 09 02 00 00 00 01-00 00 00 02 00 00 00 10  ................
    00000060  02 00 00 00 04 00 00 00-09 03 00 00 00 0D 03 0C  ................
    00000070  04 00 00 00 44 63 70 70-64 6C 6C 2C 20 56 65 72  ....Dcppdll, Ver
    00000080  73 69 6F 6E 3D 31 2E 30-2E 32 34 35 30 2E 32 34  sion=1.0.2450.24
    00000090  31 32 38 2C 20 43 75 6C-74 75 72 65 3D 6E 65 75  128, Culture=neu
    000000A0  74 72 61 6C 2C 20 50 75-62 6C 69 63 4B 65 79 54  tral, PublicKeyT
    000000B0  6F 6B 65 6E 3D 6E 75 6C-6C 05 03 00 00 00 0A 44  oken=null......D
    000000C0  41 2B 53 72 76 72 44 65-73 05 00 00 00 09 44 73  A+SrvrDes.....Ds
    000000D0  70 6C 79 4E 61 6D 65 0D-41 64 6D 69 6E 69 73 74  plyName.Administ
    000000E0  72 61 74 65 64 03 46 45-53 0A 55 73 72 50 6F 72  rated.FES.UsrPor
    000000F0  74 69 6F 6E 0D 41 6C 77-61 79 73 50 6F 72 74 69  tion.AlwaysPorti
    00000100  6F 6E 01 03 01 01 01 0E-53 79 73 74 65 6D 2E 42  on......System.B
    00000110  6F 6F 6C 65 61 6E 04 00-00 00 06 05 00 00 00 0B  oolean..........
    00000120  48 65 6C 6C 6F 20 57 6F-72 6C 64 00 06 06 00 00  Hello World.....
    00000130  00 00 09 06 00 00 00 09-06 00 00 00 0B           .............

    Tuesday, September 19, 2006 4:46 AM
  • This is from the VBDll... it's nice the the serialization file describes who wrote it

    00000000  00 01 00 00 00 FF FF FF-FF 01 00 00 00 00 00 00  ................
    00000010  00 04 01 00 00 00 1C 53-79 73 74 65 6D 2E 43 6F  .......System.Co
    00000020  6C 6C 65 63 74 69 6F 6E-73 2E 41 72 72 61 79 4C  llections.ArrayL
    00000030  69 73 74 03 00 00 00 06-5F 69 74 65 6D 73 05 5F  ist....._items._
    00000040  73 69 7A 65 08 5F 76 65-72 73 69 6F 6E 05 00 00  size._version...
    00000050  08 08 09 02 00 00 00 01-00 00 00 02 00 00 00 10  ................
    00000060  02 00 00 00 04 00 00 00-09 03 00 00 00 0D 03 0C  ................
    00000070  04 00 00 00 3C 56 42 64-6C 6C 2C 20 56 65 72 73  ....<VBdll, Vers
    00000080  69 6F 6E 3D 31 2E 30 2E-30 2E 30 2C 20 43 75 6C  ion=1.0.0.0, Cul
    00000090  74 75 72 65 3D 6E 65 75-74 72 61 6C 2C 20 50 75  ture=neutral, Pu
    000000A0  62 6C 69 63 4B 65 79 54-6F 6B 65 6E 3D 6E 75 6C  blicKeyToken=nul
    000000B0  6C 05 03 00 00 00 13 56-42 64 6C 6C 2E 53 44 61  l......VBdll.SDa
    000000C0  74 61 2B 53 72 76 72 44-65 73 05 00 00 00 09 44  ta+SrvrDes.....D
    000000D0  73 70 6C 79 4E 61 6D 65-0D 41 64 6D 69 6E 69 73  splyName.Adminis
    000000E0  74 72 61 74 65 64 03 46-45 53 0A 55 73 72 50 6F  trated.FES.UsrPo
    000000F0  72 74 69 6F 6E 0D 41 6C-77 61 79 73 50 6F 72 74  rtion.AlwaysPort
    00000100  69 6F 6E 01 00 01 01 01-01 04 00 00 00 06 05 00  ion.............
    00000110  00 00 0B 48 65 6C 6C 6F-20 57 6F 72 6C 64 00 06  ...Hello World..
    00000120  06 00 00 00 00 09 06 00-00 00 09 06 00 00 00 0B  ................

    Tuesday, September 19, 2006 4:59 AM
  • Use a single \ in VB for the path

     



    fso = New FileStream(Application.UserAppDataPath + "\data.dbs", FileMode.OpenOrCreate)

     

    Saturday, September 23, 2006 10:38 AM
    Moderator
  • This is a known issue with the BinaryFormatter. Can you please consider changing SrvrDes.Administrated from bool^ to bool? Was it meant to be a reference (boxed) type?

    Thanks

    Wednesday, September 27, 2006 6:46 AM
    Moderator
  • Hi,

    1. When you say its a known issue with BinaryFormatter, could you please direct to references of this issue?

    2. Are there workarounds? If so, could you point to them. If not, could you please direct to what needs to be avoided?

    Thank you, Gad.

    Sunday, October 22, 2006 7:42 AM
  • Ok, i've got the same error, but with a slightly different code. I did the same - serialize then deserialize, but the result was saved to a memory stream (and then to a string). To get a string I needed an Encoder...(the same encoder was used to convert string back to byte[]).
    - I've tried UFT8, which previously worked fine, but in the given special case deserialization resulted in the same error
    - So just for fun, i've tried the Unicode encoding, and i don't know the reason why, but the code began to work...
     
    I hope this will help you to move along.
     
    And finally - if anyone can explain me why my code began to work, do it please.
    Monday, February 19, 2007 1:08 PM
  • Ive got the same error... Convert the byte[] with Encoding.Unicode to a string. It'll work. And do not use UTF8, cause then you'll get the same error as with the Base64String :-)
     
    I cannot explain it in details, hope someone will answer this post and explain me the reasons for this strange behaviour.
    Monday, February 19, 2007 1:11 PM