2010-06-23 4 views
2

На данный момент я испытываю очень неприятную проблему. Я попытаюсь отвлечь проблему, чтобы сделать ее немного легче. Он должен с сериализацией моего пользовательского объекта в базу данных в одном процессе и десериализации его в другом процессе.Deserializing memoryStream - неожиданное поведение

У меня есть два сборника; AppToDB.dll и AppFromDB.dll. У меня есть 3-я сборка - 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; 
     } 
    } 

ОК, так что в обоих кусков кода вы можете увидеть MemoryStream объект. В первом AppToDB он создается, и если я смотрю его содержимое, он содержит 707 байт. Хорошо. Я пишу его в базу данных и сохраняю там как BLOB. Теперь в AppFromDB Я извлекаю BLOB и сохраняю его в массиве byte[]. Я снова напишу массив byte[] на MemoryStream и посмотрю, что мои объекты MemoryStream содержат 707 байт, все из которых находятся на месте, как оригинал. Кажется, я успешно передал объект!

Теперь проблема заключается в object temp = oBFormatter.Deserialize(dbStream);. Как только я попытаюсь десериализовать, мой object является Прозрачным прокси, и я не могу отдать MyCustomObject !! Как вернуть исходный объект? Как в # @ & 's имя у меня есть объект MemoryStream .... В памяти ... готов к сериализации ... и вдруг это Прозрачный прокси снова.

Я нахожусь в убытке. Помощь приветствуется. Я буду молиться, чтобы # @ & для того, кто имеет ответ;)

Edit 1 ОК, я должен сказать, вещи начинают иметь смысл сейчас (хотя проблема сохраняется). Моя проблема: у меня есть объект (включая состояние) с одной стороны, и мне нужно сохранить его в базе данных, поэтому я могу использовать его через несколько дней другим процессом с другой стороны.

Мой объект не является сериализуемым, поскольку он обертывает сторонний объект, который не помечен как сериализуемый. Поэтому мой единственный вариант, похоже, заключается в маршале, который возвращает ObjRef, который, в свою очередь, сериализуется. Но, конечно, через несколько дней - объект, который я десериализую, является просто ссылкой, и мой первоначальный объект ушел.

Как решить мою проблему? Все больше людей должно быть, сталкивались с этим, и я просто не могу найти ответ ...

Edit 2 Хорошо, я предполагаю, что я собираюсь написать свой собственные сериализации класса изоморфен объекту 3 партии. Затем пропустите весь сторонний объект и сохраните/заверните его информацию о состоянии и т. Д. Затем сериализуйте мой объект в базу данных ... Кажется, это единственный вариант.

Редактировать 3 Начиная с этой проблемы снова через некоторое время. Просто понял, что решение, опубликованное в Edit 2, не будет работать. Мне нужно десериализовать объект, который знает сторонняя сборка, поскольку он будет продолжать выполнять операции над ним.

+0

возможно дубликат [Как маршал объекта и его содержимое (также объекты)] (http://stackoverflow.com/questions/3068702/how-to-marshal-an-object-and-its- content-also-objects) – Lucero

ответ

1

Вы сериализуете ObjRef, который не является исходным объектом, а скорее «ссылочной ссылкой», содержащей всю информацию для передачи ссылки.

Из MSDN (курсив мой):

ObjRef содержит информацию, которая описывает тип и класс объекта выстраивали, его точное местоположение и коммуникации, связанные с информацию о том, как добраться удаленное подразделение, в котором находится объект .

После того, как класс, реализующий MarshalByRefObject маршалируется, то ObjRef, что она представляет передается через канал в другого домена приложения, возможно, в другом процессе или компьютере. Когда ObjRef десериализуется в целевом домене приложения , это проанализирован для создания прозрачного прокси для удаленного объекта MBR. Эта операция известна как немаршалинг.

Редактировать (из-за новой информации, предоставленной):

Есть несколько подходов можно решить вашу проблему. Все они имеют свой собственный набор ограничений, которые я соединил здесь:

  • Использования XML-сериализация с XmlSerializer. Сериализация XML отличается тем, что она сериализует и десериализует все публичные свойства объекта, а не сериализует поля и/или пользовательские данные (когда ISerializable реализуется объектом, который будет сериализован). Поэтому, если сторонние объекты являются просто контейнерами данных, сериализация общедоступных свойств достаточно хороша, и они предоставляют конструктор по умолчанию, вы должны быть в порядке с этим решением.

  • Создайте собственный код сериализации низкого уровня, используя отражение, чтобы получить поля и сериализовать их. Этот подход обычно требует, чтобы ваше приложение выполнялось с полным доверием (отражение и изменение частных полей через отражение требует разрешений, которые обычно отсутствуют в более низких трастах). Некоторые методы, которые могут вам помочь, следующие: FormatterServices.GetSerializableMembers(), чтобы получить поля для сериализации, FormatterServices.GetObjectData(), чтобы получить данные полей из экземпляра объекта, FormatterServices.GetSafeUninitializedObject() при десериализации для создания нового, неинициализированного экземпляра (без вызова конструктора) и FormatterServices.PopulateObjectMembers() напишите поля обратно на новый экземпляр. Если у вас есть только простые типы данных, которые можно сериализовать в полях, вы можете сериализовать и десериализовать object[], которые вы используете для хранения данных полей.

  • Ваша текущая идея, которая заключается в том, чтобы вручную написать реплику сторонних объектов. Это может быть очень болезненным и в основном работает только тогда, когда будет работать сериализация XML. Если свойства доступны только для чтения для синаце, вам не удастся приблизиться к этому подходу.

+0

Спасибо за ваш ответ.Но теперь я действительно в потере. MyCustomObject содержит методы и информацию о состоянии - как и любой другой объект, который я должен хранить и извлекать с другого конца. Как мне это сделать?? Я работаю над этим уже несколько дней :( –

 Смежные вопросы

  • Нет связанных вопросов^_^