2011-09-08 7 views
1

Я создал двоичный сериализованный файл моего объекта, так что я мог бы использовать его в качестве файла базы данных для многих других проектов. Он работает очень хорошо с тем же проектом, но когда я пытаюсь десериализовать этот файл из других проектов, он не будет. Появившаяся ошибка говорит, что «xxxx.xxxx assembly not found». Итак, как я должен сериализовать объект, чтобы сделать его независимым от сборки ???Проблема десериализации в .NET

Вот мой код:

  // Binary formatter 
      IFormatter formatter = new BinaryFormatter(); 
      Stream stream = new FileStream("BinarySerialization.bin", 
            FileMode.Create, 
            FileAccess.Write, FileShare.None); 
      formatter.Serialize(stream, words); 
      stream.Close(); 

Какие изменения мне нужно сделать ??? Пожалуйста, предоставьте мне пример рабочего примера/образца.

Спасибо.

+1

проверка: [этот вопрос] (http://stackoverflow.com/questions/4193951/how-to-get-binaryformatter-to-deserialize-in-a-different- приложение) –

ответ

1

Я бы поставил все свои модели, которые должны быть сериализованы в отдельную сборку. Затем вы ссылаетесь на эту сборку везде, где вам нужно десериализовать Модели.

Если вам не нужен какой-то генератор, который воссоздает модели, основанные на какой-либо схеме (такие же, как WCF, с ее утилитами) или использует простые форматы, такие как XML, чтобы сохранить ваши данные.

+0

Здесь небезопасны XML, так как я не хочу, чтобы пользователи знали содержимое основного файла базы данных. Можете ли вы дать мне представление о том, как использовать assemblyBinding или какое-то другое решение? – MrClan

+0

@Pratik, если xml небезопасен, также не является 'BinaryFormatter', строго говоря –

+0

yes - BinaryFormatter получит проблемы, если вы измените свою сборку, - но помимо этого вы просто поместите все классы, которые сериализуют/десериализуют (я думаю, где вы реализуете ISerializable) в Dll-Project. Где бы вам ни понадобилось десериализовать или сериализовать эти модели, вы просто скажете «Добавить ссылку» и добавьте полученную в результате dll – Carsten

1

BinaryFormatter - это сериализованный тип; он глубоко внедряет метаданные типа в выход. Я бы сказал, что у вас есть скопировано определение класса между проектами - этого недостаточно для BinaryFormatter, так как это уже не то же самое Type (типы привязаны к их сборке).

В вашем сценарии мне кажется, что правильная вещь здесь должна заключаться в использовании договора ; например:

  • XML (XmlSerializer, DataContractSerializer и т.д.)
  • JSon (JavascriptSerializer, JSON.net и т.д.)
  • бинарный (Protobuf-сети и т.д.)

Там бы бы полностью в вашем сценарии, а также будет иметь гораздо лучший допуск к версии (BinaryFormatter очень хрупкий с версиями)

Вы упомянули, что «XMLs здесь небезопасны, так как я не хочу, чтобы пользователи знали содержимое основного файла базы данных». - в этом случае protobuf-net имеет «преимущество» от того, что он не читается человеком, но обратите внимание: ни один из них, ни BinaryFormatter не являются зашифрованными; если бы я хотел, я мог бы получить содержимое, если я действительно, действительно хотел. Если вам нужна надежная защита, используйте правильное шифрование. В этом случае ваш код становится (в дополнение к возможно несколько атрибутов маркера):

using(var stream = new FileStream("BinarySerialization.bin", FileMode.Create, 
           FileAccess.Write, FileShare.None)) 
{ 
    Serializer.Serialize(stream, words); 
} 

Редактировать, чтобы показать (в комментариях) как сериализовать Dictionary<string, List<Word>> где Word класс с 2-мя членами строки (большинство из код здесь просто сантехника, чтобы показать полный пример):

using System; 
using System.Collections.Generic; 
using System.IO; 
using ProtoBuf; 
[ProtoContract] 
public class Word { 
    [ProtoMember(1)] 
    public string Foo { get; set; }  
    [ProtoMember(2)] 
    public string Bar { get; set; } 
} 
static class Program { 
    public static void Main() { 
     var data = new Dictionary<string, List<Word>>{ 
      {"abc", new List<Word> { 
       new Word { Foo = "def", Bar = "ghi"}, 
       new Word { Foo = "jkl", Bar = "mno"} 
      }}, 
      {"pqr", new List<Word> { 
       new Word {Foo = "stu", Bar = "vwx"} 
      }} 
     }; 
     using(var file = File.Create("my.bin")) { 
      Serializer.Serialize(file, data); 
     } 
     Dictionary<string, List<Word>> clone; 
     using(var file = File.OpenRead("my.bin")) { 
      clone = Serializer.Deserialize< 
       Dictionary<string, List<Word>>>(file); 
     } 
     foreach(var pair in clone) { 
      Console.WriteLine(pair.Key); 
      foreach(var word in pair.Value){ 
       Console.WriteLine("\t{0} | {1}", word.Foo, word.Bar); 
      } 
     }  
    } 
} 
+0

«protobuf» звучит неплохо, но я думаю, для его выполнения потребуется время, так как мне придется немного поработать над этим. – MrClan

+0

@Pratik в большинстве случаев довольно тривиально переключаться между ними; Трудно сказать, так как я не могу видеть вашу модель, конечно. Если вы можете предоставить какой-то представительный пример, я могу показать вам, как это сделать. –

+0

У меня есть объект типа Dictionary > где Word является сериализуемым классом, в котором говорят два члена строки. Итак, как бы я сериализовал этот объект с protobuf ??? – MrClan

1

Механизм сериализации в.NET создает вспомогательную dll из типа для сериализации и десериализации данных во время выполнения. Сначала он выплевывает файл кода, который компилируется, а затем загружается вспомогательная dll для сериализации и десериализации.

Если по какой-то причине что-то происходит, когда создается хелпер .dll - допустим, ошибка компиляции - тогда среда выполнения не найдет эту DLL.

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

HOW TO: Debug into a .NET XmlSerializer Generated Assembly