2010-06-23 57 views
2

目前我遇到了一個非常令人沮喪的問題。我會盡量抽象出這個問題,讓它更容易一些。它必須在一個進程中將我的自定義對象序列化到數據庫,並在另一個進程中對其進行反序列化。反序列化MemoryStream - 出乎意料的行爲

我有兩個組件; AppToDB.dllAppFromDB.dll。我有第三個程序集 - MyCustomObject.dll - 這兩個程序集都包含一個引用。 MyCustomObject.dll延伸MarshalByRefObject

在我AppToDB.dll我執行下面的代碼:

public bool serializeToDB(MyCustomObject obj) 
    {    
     OdbcDataAdapter da = new OdbcDataAdapter(); 
     MemoryStream memStream = new MemoryStream(); 

     try 
     { 
      ObjRef marshalledObj = RemotingServices.Marshal((System.MarshalByRefObject)obj); 

      // Serialize the object; construct the desired formatter 
      IFormatter oBFormatter = new BinaryFormatter(); 

      // Try to serialize the object 
      oBFormatter.Serialize(memStream, marshalledObj); 

      // Create byte array 
      byte[] serialized = memStream.ToArray(); 

      // Build the query to write to the database 
      string queryString = 
        "INSERT INTO MyCustomObject(id, object) VALUES(?, ?)"; 
      OdbcCommand command = new OdbcCommand(queryString, connection); 
      command.Parameters.AddWithValue("id", 1); 
      command.Parameters.AddWithValue("object", serialized); 

      // Write the object byte array to the database 
      int num = command.ExecuteNonQuery(); 
    } 
    catch { } 
} 

AppFromDB.dll我執行此代碼:

public OCR.Batch deserializeFromDB() 
    {    
     MemoryStream memStream = new MemoryStream(); 

     try 
     { 
      string queryString = "SELECT object FROM FCBatch"; 
      OdbcCommand command = new OdbcCommand(queryString, connection); 
      OdbcDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess); 

      // Size of the BLOB buffer. 
      int bufferSize = 100; 
      // The BLOB byte[] buffer to be filled by GetBytes. 
      byte[] outByte = new byte[bufferSize]; 
      // The bytes returned from GetBytes. 
      long retval; 
      // The starting position in the BLOB output. 
      long startIndex = 0; 

      MemoryStream dbStream = new MemoryStream(); 

      while (reader.Read()) 
      { 
       // Reset the starting byte for the new BLOB. 
       startIndex = 0; 

       // Read bytes into outByte[] and retain the number of bytes returned. 
       retval = reader.GetBytes(0, startIndex, outByte, 0, bufferSize); 

       // Continue while there are bytes beyond the size of the buffer. 
       while (retval == bufferSize) 
       { 
        dbStream.Write(outByte, 0, bufferSize); 
        dbStream.Flush(); 

        // Reposition start index to end of last buffer and fill buffer. 
        startIndex += bufferSize; 
        retval = reader.GetBytes(0, startIndex, outByte, 0, bufferSize); 
       } 

       // Write the remaining buffer. 
       dbStream.Write(outByte, 0, (int)retval); 
       dbStream.Flush(); 
      } 
      // Close the reader and the connection. 
      reader.Close(); 

      dbStream.Position = 0; 
      object temp = oBFormatter.Deserialize(dbStream); 
      MyCustomObject obj = (MyCustomObject)temp; 

      return null; 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
      return null; 
     } 
    } 

OK,所以在這兩個代碼段,你可以看到一個MemoryStream對象。在第一個AppToDB它被創建,如果我看它的內容它包含707個字節。精細。我將它寫入數據庫並將其保存爲BLOB。現在在AppFromDB我檢索BLOB並將其存儲在byte[]陣列中。我再次將byte[]數組寫入MemoryStream,並看到我的MemoryStream對象包含707個字節,所有這些都與原始位置一樣。看來我已經成功轉移了這個對象!

現在問題在於object temp = oBFormatter.Deserialize(dbStream);。只要我嘗試反序列化,我的object是透明代理,我無法投射到MyCustomObject!我如何獲得我的原始對象?如何在#@ &的名稱可以有一個MemoryStream對象....在內存中...準備好被序列化...突然它又是一個透明代理服務器。

我不知所措。幫助表示讚賞。我會祈求#@ &對於誰擁有了答案之一;)

編輯1 OK,我必須說,事情開始變得有意義,現在(雖然問題仍然存在)。我的問題:我在一邊有一個對象(包括狀態),我需要將它存儲在數據庫中,以便日後可以在另一端使用另一個進程。

我的對象不可序列化,因爲它包裝了未標記爲可序列化的第三方對象。所以我唯一的選擇似乎是編組,它返回一個ObjRef,它反過來是可序列化的。但是當然 - 幾天之後 - 我反序列化的對象僅僅是參考,我的原始對象已經消失了。

我該如何解決我的問題?更多的人一定都遇到過這一點,我似乎無法找到答案......

編輯2 OK,我想我會寫我自己的序列化的類同構於第三方對象。然後運行整個第三方對象,並存儲/包裝其狀態信息等,然後序列化我的對象到數據庫...似乎是我唯一的選擇。

編輯3 過了一段時間再次開始這個問題。剛剛意識到,雖然解決方案張貼在編輯2將無法正常工作。我必須反序列化第三方程序集所知道的對象,因爲它將繼續對它執行操作。

+0

可能重複[如何編組對象及其內容(也是對象)](http://stackoverflow.com/questions/3068702/how-to-marshal-an-object-and-its- content-also-objects) – Lucero 2010-06-23 19:31:47

回答

1

您正在序列化ObjRef這不是原始對象,而是一個「遠程引用」,其中包含傳輸引用的所有信息。

從MSDN(重點煤礦):

的的ObjRef包含 描述 對象的被編上如何到達類型和類別,其確切 位置,通信相關 信息 遠程細分對象 所在的位置。

後實施 MarshalByRefObject的一類被編組,所述 的ObjRef表示它是 在另一個進程或計算機通過信道轉移到另一個 應用領域,可能 。當 ObjRef在 目標應用程序域中被反序列化時,它被解析爲爲遠程MBR對象創建透明代理 。這種操作稱爲解組。

編輯(因爲所提供的新信息):

有解決你的問題的幾種方法成爲可能。他們都有自己的一套限制,我將在這裏放一起的:與XmlSerializer

  • 使用XML序列化。 XML序列化的不同之處在於,它序列化和反序列化對象的所有公共屬性,而不是序列化字段和/或自定義數據(當ISerializable由要序列化的對象實現時)。因此,如果第三方對象僅僅是數據容器,序列化公共屬性就足夠好,並且它們提供了一個默認的構造函數,您應該對這個解決方案很好。

  • 構建您自己的「低級」序列化代碼,使用反射來獲取字段並序列化這些字段。這種方法通常要求您的應用程序以完全信任的方式運行(通過反射來反映和修改私有字段需要權限,而這些權限通常不存在於較低級的信任中)。在這裏可以幫助你的一些方法如下:FormatterServices.GetSerializableMembers()獲取字段序列化,FormatterServices.GetObjectData()從對象實例獲取字段數據,FormatterServices.GetSafeUninitializedObject()當開始去創建一個新的,未初始化的實例(沒有構造函數被調用),FormatterServices.PopulateObjectMembers()將字段寫回到新的instane。如果只有在字段中可序列化的簡單數據類型,則可以序列化和反序列化用於存儲字段數據的object[]

  • 您當前的想法是手動編寫第三方對象的副本。這可能是非常痛苦的,基本上只有在XML序列化工作時纔有效。如果屬性對於sinatce是隻讀的,那麼使用這種方法就不會有太大的改進。

+0

謝謝你的回答。但現在我真的處於虧損狀態。 MyCustomObject包含方法和狀態信息 - 就像任何其他對象一樣 - 我必須在另一端存儲和檢索它們。我該怎麼做??我一直在這個工作幾天現在:( – 2010-06-23 10:35:09