I'm serializing some data like fields and custom class to create a binary data (byte array).
Then I want to Deserialize it back from binary data to fields and class.
But I get an exception. It would all work fine if these two methods would happen in same assembly - but its not.
I do Serialization in one assambly, and do the Deserialization in another one. And this is the excaption saying too:
Unable to find assembly 'MyAssamblyName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
NOTE 1: I have no issues with getting the fields back, only the classes causes them.
NOTE 2: I have this same class in both assemblies.
NOTE 2: I have this same class in both assemblies
No you don't. At least, not as far as the runtime is concerned. You have two different types that happen to have the same name. A type is defined by its assembly. Thus "SomeType in AssemblyA" is completely different to "SomeType in AssemblyB", even if they happen to have been compiled from the same source file.
BinaryFormatter works with type information, so this won't work. One option would be to move the type to a library dll that both the other projects reference - then it is only defined once, and it will be happy.
Another option is to work with a contract-based serializer (rather than a type-based serializer). This means that "classes that look similar enough" are fine, even if they are in different assemblies (and perhaps have different source, as long as it is "similar enough"). Examples of suitable serializers for this would include (plus a few others) XmlSerializer, DataContractSerializer (but not NetDataContractSerializer), JavaScriptSerializer, or protobuf-net if you want dense raw binary.
All the assemblies containing classes in the class hierarchy of the object you are deserializing must be present in the application in which you are performing this deserialization. They could be either explicitly referenced (if you need compile-time safety with those classes) or only placed in the bin folder of the application so that they could be resolved at runtime. If they are not explicitly referenced you will have to use reflection in order to read the values from the deserialized instance.
Related
I have an architecture consisting of two DLLs and one executable. Both DLLs define a class with the same name and namespace, but potentially different implementations. What I would like to do is to create an object of each of those classes, and have both of them coexist at the same time.
But as we know a picture says more than a thousand words, so here you go:
The surprising thing is: it actually seems to work!
I have implemented a small prototype using lots of reflection to load the DLLs and instantiate the objects.
Now my question is: Why does this work?
Shouldn't there be a problem having both of the classes in the same AppDomain?
Is it safe to do it this way, or did I just get lucky?
A type is more than its class name and namespace. It also includes assembly information to qualify it. You can compare the AssemblyQualifiedName property of any System.Type and see that they are different.
I am encountering a really weird Exception on one of my application (later referenced as ApplicationB)
`Unable to find assembly 'MsgPack, Version=0.5.0.0, Culture=neutral, PublicKeyToken=a2625990d5dc0167'.`
Here is my scenario, on my ApplicationA I have serialized an object using MsgPack and store it into Redis using SE.Redis. Later on, I query this object and deserialize it (of course still using MsgPack). Once this is done, I am sending this object via a TCP/Componennt that serializes this same object using BinaryFormatter. On the other side, ie on ApplicationB, once the packet arrived, it is deserialized using BinaryFormatter and this is where I get the exception.
I don't have any control on the TCP/Component and the serializer it uses.
So why do I get this error on ApplicationB which should know any thing about MsgPack?
Just a thought I want to share, it seems that MsgPack create on the fly DataContract and when deserializing, it might applies some attributes on the object that conflict with the BinaryFormatter. Of course I am not sure about that.
But has anyone encountered this problem?
Cheers.
EDIT: I noticed that for member of type object, MsgPack adds a lot of members for defining the type store in the object member (like IsDictionary, IsList, etc.). Does it impact BinaryFormatter?
When using binary serialization, only the fully qualified type name and its data is serialized to a byte-array. The serializer on the other side wants to deserialize its data. It first reads the type name from the byte-array and tries to find and instanciate that type. That type must be somewhere in a DLL. So it looks for the given DLL (in your case MsgPack) but it cannot be found. Thus: Make sure the DLL MsgPack is located on both sides.
If it is not possible to to have the DLL on the other side, your could try to serialize the DLL itself and send it over to the other side. First deserialize the DLL, put it inside your bin folder or load it into memory, then deserialize the type with its data. But you must really, really, really make sure if you wanna do that. I wouldn't.
Have you ever considered communicating between AppA en AppB using WCF?
I have two separate programs that need to share information. This sharing will be done by one app placing an XML serialized object in a database, and the other app retrieving it on a different machine. The objects share the same variables but the properties and methods are different.
How exact do the classes have to match between the two programs?
Is the match line by line or just variable, property, and method names?
I ended up using the Newtonsoft.Json library instead of xml and used the <JsonObject(MemberSerialization.OptIn)> and JsonProperty() attributes to control what got serialized.
You did not specify which kind of serialization you were after.
The standard NET binary serializer is not well suited for data exchange between 2 different assemblies. When you go to deserialize, you'll get an an error similar to [Culture].[Assembly].[Version].SourceClass cannot be deserialized to [Culture].[Assembly].[Version].DestClass. This will happen even if the classes are identical.
There are several ways around this. A) Use the same service DLL on both sides to do the serializing B) trick it into deserializing by using an override to report a matching Culture-Assembly-Version-Class, but that seems dodgy or C) use XML serialization, but that makes for very wordy output, which is also readable.
For Binary Serialization, rather than the NET binary formatter, there is ProtoBuf-NET which is faster, produces much smaller output and uses nearly identical syntax.
How exact do the classes have to match between the two programs
ProtoBuf uses a numeric index rather than property name, so they shouldn't have to be too similar. Of course there has to be some similarity or the destination may not have a clue what the data represents. The code in the class can be quite different because it stays put.
Serialization stores only the data for an object - member variables, properties, etc. As long as the data types are compatible, it should work. You do not need a line by line match for the functions.
It all depends on the serializer you are using. Some require a perfect match, others tend to be more loosely coupled to the objects.
How exact do the classes have to match between the two programs?
Well, not at all. But they should be similar in some way because otherwise the serialization doesn't make sense.
Is the match line by line or variables and method names?
As, stated above: there must be some overlap. Usually the property names must be the same. But of course you can also provide a custom mapping.
Take a look at the Newtonsoft library, u can use it (for json) like this:
JsonConvert.DeserializeObject<IEnumerable<Unit>>(result);
It's independent of the object method that serialized the string.
System.Runtime.Serialization.SerializationException:
Type 'System.Threading.Thread' in Assembly 'mscorlib, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.
Is there a way around that? ive added the Serializable attribute to all of my class's, but i cant add attributes to things like that, can i? and if i can, is there a way to get around that issue altogether? because i dont want to always have to add [Serializable] to everything.
PS, in my project, im dynamically compiling C# code and including it in my application.
edit one: Because of the nature of my application, everything, all events, etc, is managed my separate threads.. I cannot get away from that fact, because i need to be doing many tasks at the same time. Is there a way to get around that fact?
One option would be to mark the thread object (and anything else you don't want serialized) as [NonSerialized].
You can then use whatever information you've serialized to reconstruct the non serialized objects.
You can't serialize a thread, so your best bet would be to remove the dependency on Thread from any class that you need to serialize. Usually you want your serializable objects to be composed mainly of primitive fields, or references to other objects that are also serializable.
[NonSerializable] is mispelled it should be [NonSerialized]
I write a desktop application that can open / edit / save documents.
Those documents are described by several objects of different types that store references to each other. Of course there is a Document class that that serves as the root of this data structure.
The question is how to save this document model into a file.
What I need:
Support for recursive structures.
It must be able to open files even if they were produced from slightly different classes. My users don't want to recreate every document after every release just because I added a field somewhere.
It must deal with classes that are not known at compile time (for plug-in support).
What I tired so far:
XmlSerializer -> Fails the first and last criteria.
BinarySerializer -> Fails the second criteria.
DataContractSerializer: Similar to XmlSerializer but with support for cyclic (recursive) references. Also it was designed with (forward/backward) compatibility in mind: Data Contract Versioning. [edit]
NetDataContractSerializer: While the DataContractSerializer still requires to know all types in advance (i.e. it can't work very well with inheritance), NetDataContractSerializer stores type information in the output. Other than that the two seem to be equivalent. [edit]
protobuf-net: Didn't have time to experiment with it yet, but it seems similar in function to DataContractSerializer, but using a binary format. [edit]
Handling of unknown types [edit]
There seem two be two philosophies about what to do when the static and dynamic type differ (if you have a field of type object but a, lets say, Person-object in it). Basically the dynamic type must somehow get stored in the file.
Use different XML tags for different dynamic types. But since the XML tag to be used for a particular class might not be equal to the class name, its only possible to go this route if the deserializer knows all possible types in advance (so that he can scan them for attributes).
Store the CLR type (class name, assembly name & version) during serialization. Use this info during deserialization to instantiate the right class. The types must not be known prior to deserialization.
The second one is simpler to use, but the resulting file will be CLR dependent (and less sensitive to code modifications). Thats probably why XmlSerializer and DataContractSerializer choose the first way. NetDataContractSerializer is not recomended because its using the second approch (So does BinarySerializer by the way).
Any ideas?
The one you haven't tried is DataContractSerializer. There is a constructor that takes a parameter bool preserveObjectReferences that should handle the first criteria.
The WCF data contract serializer is probably closest to your needs, although not perfect.
There is only limited support for backwards compatibility (i.e. whether old versions of the program can read documents generated with a newer version). New fields are supported (via IExtensibleDataObject), but new classes or new enum values not.
I would think the XmlSerializer is your best bet. You won't be able to support everything on your requirements list without a bit of work in your Document classes - but the XmlSerializer architecture gives you extensibility points which should allow you to tap into its mechanism deep enough to do just about anything.
Using the IXmlSerializable interface - by implementing that on your classes you want to store - you should be able to do just about anything, really.
The interface exposes basically two methods - ReadXml And WriteXml
public void WriteXml (XmlWriter writer)
{
// do what you need to do to write out your XML for this object
}
public void ReadXml (XmlReader reader)
{
// do what you need to do to read your object from XML
}
Using these two methods, you should be able to capture the necessary state information from just about any object you might want to store, and turn it into XML that can be persisted to disk - and deserialized back into an object when the time comes!
XmlSerializer can work for your first criteria, however you must provide the recursion for objects like the TreeView control.
BinaryFormatter can work for all 3 criteria. If a class changes, you may have to create a conversion tool to convert old format documents to a new format. Or recognize an older format, deserialize to the old, and then save to the new - keeping your old class format around for a little while.
This will help cover version tolerance which is what I think you're after: MSDN - Version Tolerant Serialization