3

I created a binary serialized file of my object, so that I could use it as a database file for many other projects. It works quite fine with the same project, but when I try to deserialize that file from other projects, it won't. The error that appears says, "xxxx.xxxx assembly not found". So, how should I serialize the object in order to make it assembly independent???

Here's my code :

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

What amendments do I need to do??? Please provide me with a working code example/sample.

Thanks.

MrClan
  • 6,402
  • 8
  • 28
  • 43
  • 2
    check: [this question](http://stackoverflow.com/questions/4193951/how-to-get-binaryformatter-to-deserialize-in-a-different-application) – Piotr Auguscik Sep 08 '11 at 05:43
  • Possible duplicate of [How to get BinaryFormatter to deserialize in a different application](https://stackoverflow.com/questions/4193951/how-to-get-binaryformatter-to-deserialize-in-a-different-application) – jrh Oct 08 '19 at 14:45
  • Note that [this answer](https://stackoverflow.com/a/25606077/4975230) shows some builtin options for handling serializing to different types that might reside in different applications. I recommend looking into [Binder](http://www.diranieh.com/NETSerialization/BinarySerialization.htm#Advanced%20Serialization) before giving up on `BinaryFormatter` or bringing in third party libraries. – jrh Oct 08 '19 at 14:48

3 Answers3

2

BinaryFormatter is a type-based serialized; it deeply embeds type metadata into the output. I would wager that you have copied the class definition between the projects - that isn't enough for BinaryFormatter, since that is no longer the same Type (types are bound to their assembly).

In your scenario, it sounds to me that the correct thing to do here would be to use a contract-based serializer; for example:

  • xml (XmlSerializer, DataContractSerializer, etc)
  • json (JavascriptSerializer, JSON.net, etc)
  • binary (protobuf-net, etc)

There would would entirely in your scenario, and would also have much better version tolerance (BinaryFormatter is very brittle with versions)

You mention "XMLs aren't safe here, as I don't want the users to know the contents of the main database file." - in that case protobuf-net has the "advantage" of being not human-readable, but note: none of these, nor BinaryFormatter are encrypted; if I wanted to, I could obtain the contents if I really, really wanted to. If you need strong security, use proper encryption. In which case your code becomes (in addition to maybe a few marker attributes):

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

Edit to show (per comments) how to serialize Dictionary<string, List<Word>> where Word is a class with 2 string members (most of the code here is just plumbing to show a complete example):

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);
            }
        }    
    }
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • "protobuf" sounds good, but I guess it would take time to implement it, as I'll have to do a bit of research on it. – MrClan Sep 08 '11 at 06:03
  • @Pratik in most cases it is pretty trivial to swap over between them; hard to say since I can't see your model, of course. If you can provide some sort of representative example I can show you how to do it. – Marc Gravell Sep 08 '11 at 06:12
  • I have an object of type Dictionary> where Word is a serializable class with say two string members inside. So, how would I serialize this object with protobuf??? – MrClan Sep 08 '11 at 06:20
  • @Marc, out of curiosity how much more work would go into the protobuf example if I for example wanted to treat null/empty strings and null/empty lists as semantically different in the serialized object "data" here? Can protobuf-net be persuaded to handle that by global configuration rather than adding more properties (HasFooValue) to the serializable objects to handle these differences? – Anders Forsgren Sep 08 '11 at 07:22
  • @Anders the protobuf wire spec *has no meaning of* `null`, so I can't really do many simple things without making it non-compliant – Marc Gravell Sep 08 '11 at 07:28
  • @Marc, I don't think it has a notion of object identity either :) but you managed to squeeze that into it anyway, making it a lot more useful than a vanilla pb serializer. I think you should make a variant of the serializer that is non-compliant with the wire format, and instead is "more .net", i.e. knows the difference between null and empty for example. It would be extremely useful to be able to serialize an object model without worrying whether it has any object that believes null and empty are different. ' – Anders Forsgren Sep 08 '11 at 07:41
  • @Anders yes, it could indeed be done in that scenario, but it adds a little overhead. – Marc Gravell Sep 08 '11 at 08:04
1

I would put all my models that have to be serialized into a seperate assembly. Then you reference this assembly everywhere you need to deserialize the Models.

If not you need some kind of generator, that recreates the models based on some schema (same as WCF does with its utilities) or use plain formats like XML to persist your data.

Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • XMLs aren't safe here, as I don't want the users to know the contents of the main database file. Can you give me an idea on how to use assemblyBinding or some other solution like that??? – MrClan Sep 08 '11 at 05:55
  • @Pratik if xml isn't safe, neither is `BinaryFormatter`, strictly speaking – Marc Gravell Sep 08 '11 at 06:00
  • yes - the BinaryFormatter will get issues if you change your assembly - but aside from this you just put all your classes that serialize/deserialize (I guess where you implementet ISerializable) into a Dll-Project. Wherever you need to deserialize or serialize those models you just say Add Reference and add the resulting dll – Random Dev Sep 08 '11 at 06:02
  • @Mark I'm not expecting such savvy users for my project who would be able to deserialize the binaries. :) – MrClan Sep 08 '11 at 06:14
1

The serialization mechanism in .NET creates a helper dll out of the type to serialize and deserialize your data in runtime. First it will spit out a code file that gets compiled and then the helper dll is loaded to do the serialization and deserialization.

If for some reason something happens while the helper .dll gets created - let's say a compilation error- then the runtime will not found this dll.

If the dll name in your case is some random character then I would say you are facing the problem described above. You can troubleshoot this by switching on an undocument switch. See the following article:

HOW TO: Debug into a .NET XmlSerializer Generated Assembly

gyurisc
  • 11,234
  • 16
  • 68
  • 102