Deserialization backwards compatibility - c#

I am trying to deserialize "SomeClass" with an older version of an application. I get this below exception
System.Runtime.Serialization.SerializationException: The ObjectManager found an invalid number of fixups. This usually indicates a problem in the Formatter.
Deserialization throws exception when I serialize version 0.9 and try to deserialize using version 0.8. I thought the OptionalField attribute would do the trick, but it didn't.
// Version 0.8
[Serializable()]
class Foo{
Bar b;
}
// Version 0.9
[Serializable()]
class Foo{
Bar b;
[OptionalField]
Zoo z;
}
Given that I cannot change version 0.8, how should I add more state to Foo object such that previous versions can deserialize whatever they can?
Any pointer will be really appreciated.
Update 1
Bar and Zoo are other classes which are serializable and contains Hashtables and other serializable stuff. Everything is serializable in those classes.
Also, I don't have any struts.

First, never NEVER use the CLR's serialization functions for anything that resembles long-term storage. We make that mistake usually once, put objects in a blob database field and pat ourselves in the back thinking we're clever. And then the CLR gets a patch or our assemblies change versions and you're screwed. So don't do it.
If you still want to do it, the best way to manage the problem is to create your own SerializationBinder that looks something like this:
public sealed class CustomBinder : SerializationBinder {
public override Type BindToType(string assemblyName, string typeName) {
Type typeToDeserialize = null;
if (typeName.IndexOf("SomeType") != -1) {
typeToDeserialize = typeof(Foo.Bar.Bax.NewType);
}
else if (typeName.IndexOf("SomeOtherType") != -1) {
typeToDeserialize = typeof(Foo.Bar.Bax.SomeOtherNewType);
}
else {
// ... etc
}
return typeToDeserialize;
}
}
Set the Binder property of the formatter you're using prior to deserializing so that it overrides the defaults.
Note that I'm not offering a drop-in solution here, I'm recommending how to solve the problem. Once you've converted out of whatever you're doing, investigate other serialization technologies like protobuf, or write your own. Either way you should never rely on the CLR for long-term serialization support.

If constructors for each version are compatible (e.g. there is a parameterless or Foo(Bar b) constructor for both versions) you can call
BinaryFormatter formatter = new BinaryFormatter();
formatter.AssemblyFormat = Formatters.FormatterAssemblyStyle.Simple;
Before deserializing your stream.

As an advisory to people investigating this issue "before it is too late"... I strongly advise against persisting via BinaryFormatter. It is OK for transient transfer between 2 app-domains that are in sync, but that is about it IMO. Other serialization tools exist that don't have these issues. In terms of binary, protobuf-net is a pretty reasonable option - allowing add/remove/rename etc without pain.

It seems that one way to do this would be to have a versioned object, that way you could try deserializing the object using the latest version. If that didn't work, step back a version until it's successful. Then once you have your object, update it to the latest version of the object and use default values for any fields you don't have data for.

The optional field attribute should have done the trick. Can you post the actual classes that you are trying to serialize.
You could try these things first -
convert structs if any to classes
try Soap Serialization instead of binary serilization

Related

C# Serialization - Could not find the assembly

I am working on C# TCP Server-Client programming. My problem is simple but somehow i couldnt figure it out.
I have an object i would like to seriliaze this object send over socket and deserialize client side. But problem is with deserializing. I serialize object with binaryformatter. Actually i am getting the actual byte array i should. But somehow while deserializing i am getting
System.Runtime.Serialization.SerializationException: 'Multi Server,
Version=1.0.0.0, Culture=neutural, PublicTokenKey=Null' assembly could
not found.
When i try to deserialize on the server side after serializing it has no problem.
I tried to customize binder which didnt work also. I really appriciate if somebody could help me.
If I'm guessing correct, you have 2 projects - "Multi Client" and "Multi Server".
You serialize object defined in "Multi Server" and then you have a copy of that class in "Multi Client".
So you serialize an object "MultiServer.SomeClass" and then you want to make it a "MultiClient.SomeClass". This ain't gonna work.
You need to create a common dll project (let's name it "MultiCommon", where you will put your class, and reference it by both "MultiServer" and "MultiClient". In this way, you will serialize and deserialize not "MultiServer.SomeClass" but "MultiCommon.SomeClass".
It sounds like you're using BinaryFormatter, in which case frankly I think the most valuable advice would be: don't do that. The data format of BinaryFormatter is fundamentally tied to your exact implementation details, making it very hard to a: have different code at different ends (meaning: deployment is very hard and brittle - everywhere needs to change at the same time), or b: revise the implementation over time.
Frankly, I would strongly advise looking at alternative serialization tools. I'm hugely biased, but protobuf-net works very well for this type of scenario; it is still "binary" (meaning: not text), but it isn't tied to the internal implementation details. It is fast (usually much faster than BinaryFormatter), efficient (usually much less bandwidth required than BinaryFormatter), free, and is usually very easy to apply to an existing object model; it usually means going from this:
[Serializable]
public class Custom {
public int Id {get;set;}
public string Name {get;set;}
// ...etc
}
to this:
[ProtoContract] // you can keep the [Serializable] for compat if you want
public class Custom {
[ProtoMember(1)]
public int Id {get;set;}
[ProtoMember(2)]
public string Name {get;set;}
// ...etc
}

when we serialize serializable object using JSON.Net, JSON string is different from DatacontractJSON serializer

I have a class some thing like below
[Serializable]
public class sample
{
private int m_width;
private int m_height;
public int Width
{
get
{
return this.m_width;
}
set
{
this.m_width = value;
}
}
public int Height
{
get
{
return this.m_height;
}
set
{
this.m_height = value;
}
}
}
If I use DataContractJsonSerializer to serialize the object of this class i get the json string as below:
{"m_height":1345,"m_width":1234}
If I use Newtonsoft.Json.dll to serialize this I am getting the out put like below:
{"Width":1234,"Height":1345}
Why DataContractSerializer using backing fields for serialization if class marked as serializable ?
Is there any way I can achieve the same thing using Newtonsoft.Json.dll
We have some objects which are marked as [Serializable] so they can be serialised using traditional methods, but which we need to have cleanly serialised in JSON for use with Web API. Setting IgnoreSerializableAttribute to true will stop Newtonsoft.Json from behaving like Microsoft's serialisers and instead it will just serialise the public properties.
TLDR: Add this to WebApiConfig.cs:
((Newtonsoft.Json.Serialization.DefaultContractResolver)config.Formatters.JsonFormatter.SerializerSettings.ContractResolver).IgnoreSerializableAttribute = true;
Unless you are always communicating from WCF to WCF, your best bet is probably going to be to use the Newtonsoft serializer. Unfortunately, the MS serializer seems to follow some Microsoft-specific standards that do not match the standards that many web apps expect.
Newtonsoft's serializer seems to be more standard, and even MS uses it for WebAPI, and in the Web API http client (nuget will pull it down for you).
Here's another difference that you will find -- try serializing a DateTime type. You will find that the DataContract serialzer serializes the value in a different format that is not compatible with other JSON (you will notice some slashes in it). My understanding is that that alternate format was used by some of the AJAX WebForm controls, but it's specific to Microsoft Webforms.
Here's a little more info about the dates: http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx
Here's another thing you might look at:
The differences between DataContractJsonSerializer and Newtonsoft still stand, but as for why you are getting the weird serialization behavior -- you are mixing your serialization standards.
The [Serializable] attribute pertains to the older .Net serialization. DataContractSerialization is backward compatible, but the behavior might be different.
If you want to do this the datacontract way, mark you class with the
[DataContract] attribute instead, and mark each public member that you want to serialize with the [DataMember] attribute. (or remove all serialization attributes, and it should default to all public properties)
That should explain the difference that are seeing, but I would still recommend that you prefer the Newtonsoft serializer.
DefaultContractResolver class in Newtonsoft.Json.dll i found some code which is setting IgnoreSerializableAttribute property to true.
#if !(SILVERLIGHT || NETFX_CORE || PORTABLE || PORTABLE40)
IgnoreSerializableAttribute = true;
#endif
I am using the DotNet4.0 dll so this property set to true and it is ignoring the Serializable attribute. if i make it false it is giving the same output as DataContractSerializer
DataContract serializer requires you to explicitly mark the class with the [DataContract] attribute and then mark each desired property to be serialized with the [DataMember] attribute.
If you do that you will find that the same json string will get out as using the other class.
The issue you are encountering is due to differences of how the 2 serializers treat the default serialization (without additional information specified):
DataContract serializes all private fields unless otherwise specified
NewtonSoft serializes all public properties unless otherwise specified
On how you can make Newtonsoft serialize the private fields i have no other idea than making a wrapper class with m_Width and m_Height properties that on the setters and geters put the values in the correct target properties of the actual object

Deserialization of changed class

I am working on a program, where I save it's project files by serializing Project class.
Because I am still working on it, some classes, that are part of Project class, do change from time to time (e.g. class got new property). It makes "simple" deserialization impossible.
Is there any way to solve it ? I mean, without writng custom serializer ? (which probably is something high above my level for now)
Just in case, I am using BinaryFormatter.
I hope I understood your problem correctly. You have a class serialized to a file which you have since changed in the program (e.g you have added another property). Now you want to deserialize this class from the file. This is not a problem as long as you have only added new properties. They will be ignored by the deserializer. It creates a new instance of your class (that is the reason why serializable classes have to have a default constructor) and tries to fill the properties it finds in the stream to derserialize. If you change a property's type or remove a property, you won't be able to deserialize the original file.
One workaround for removing properties is to keep them in the class, but just stop using them in the rest of the program. A workaround for properties that have been changed to a different type could look something like this:
[Serializable]
public class MyClass
{
int? newProperty;
[XmlElement("Property")]
public string OldProperty
{
get { return string.Empty; }
set
{
if (!newProperty.HasValue)
{
int temp;
if (int.TryParse(value, out temp))
{
newProperty.Value = temp;
}
}
}
}
public int NewProperty
{
get { return newPropery.HasValue ? newProperty.Value : 0; }
set { newProperty.Value = value; }
}
}
From my experience, I've found using BinaryFormatter for serialization/de-serialization of data types that are going to change a really bad idea. If something changes in your data type, from what I know the BinaryFormatter will fail in the process.
To overcome this issue in the data types I was using, I had to write my own serializer, which wasn't actually that much of a major task. You can use the BinaryReader and BinaryWriter classes to read and write the data in and out of your type. That way you can control the data you are expecting and handle any missing data either by adding default values, skipping the property altogether, or throwing some form of Exception to signify corrupt data. Refer to the MSDN article links above for more information.
With help from Merlyn Morgan-Graham's comments I've found solution, that will work for me.
Versioning described in Version Tolerant Serialization is really good idea, but when I use only [Serializable] attribute.
I forgot to write (my mistake), that I am using ISerializable interface.
I've found, that in deserialization constructor SerializationInfo object has MemberCount property, which solves my problem if I only add new properties/members from time to time. With this information, new members/properties, that can't be deserialized from older file, can be set to default or maybe I can use some prompt form.
Other way here would be using something like assembly version in deserialization, as a first deserialized member. This can solve deserialization problems with more complex class changes.
Either way, I agree with Merylin - "if you can't script something, you shouldn't be building it". ;)

Null reference exceptions during Base64 deserialization (C#)

I am using the following methods to serialize and deserialize .NET objects:
public static string SerializeToBase64(object data)
{
var stream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize(stream, data);
stream.Position = 0;
return Convert.ToBase64String(stream.ToArray());
}
public static object DeserializeFromBase64(string data)
{
var stream = new MemoryStream(Convert.FromBase64String(data));
stream.Position = 0;
var formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
These methods seem to work fine when working with simple classes marked with the [Serializable] attribute.
But I need to use this code to serialize entity classes (also maked as Serializable) created by an ORM framework, whereby each entity class is derived from a base class for which I do not have source code.
When working with instances of an entity class, it completes serialization without exceptions, but deserialization always throws a null reference exception when excecuting formatter.Deserialize().
I am not very familiar with the process of serialization, but I assume this problem must be caused by something anomalous in the state of the target object. Is there a standard set of criteria that an object must meet before serialization?
Any other debugging suggestions would be appreciated.
Thanks,
Tim
UPDATE:
After further experimentation, I think I have discovered the cause of the problem. The target object has events that are handled by another class that is not marked as serializable, as described in this post.
What's interesting is that serialaztion works correctly, even with the event handlers attached - it's deserialization that fails.
But I have tested by temporarily removing the event handlers and both serialization and deserialization works correctly, so I assume this is the problem. However, since I don't have access to the code in which the events are declared, I can't immediately see how to implement the solution described above. It may be that I have to modify my serialization process to remove and then reinstate the event handlers.
Which ORM framework is it? Note that ORM-generated types tend to be particularly obnoxious when used with BinaryFormatter, since they aren't always "POCO": they often have fields that relate to the ORM - so creating them standalone has issues. In short, I'm not hugely surprised that it doesn't work in this case.
You might want to consider using something like DataContractSerializer, XmlSerializer, protobuf-net, or maybe NetDataContractSerializer - these all do a similar job, but because they work on public properties (rather than fields) they tend to be more effective - and indeed many have inbuilt support for these approaches for use as a DTO.
Can you use Reflector on the ORM base class assembly? There could be some custom deserialization code which is causing the exception (i.e. it implements the ISerializable interface). If you can find out of that is the case, and what it is doing, you might be able to set enough state in the subclass' instance to keep it from happening. On the other hand, if it has a bug, then you're a bit out of luck.

How to use XmlSerializer to deserialize into an existing instance?

Is it somehow possible to use the XmlSerializer to deserialize its data into an existing instance of a class rather than into a new one?
This would be helpful in two cases:
Easily merge two XML files into one object instance.
Let object constructer itself be the one who is loading its data from the XML file.
If the is not possible by default it should work by using reflection (copying each property after the deserialisation) but this would be an ugly solution.
Basically, you can't. XmlSerializer is strictly constructive. The only interesting thing you can do to customize XmlSerializer is to implement IXmlSerializable and do everything yourself - not an attractive option (and it will still create new instances with the default constructor, etc).
Is xml a strict requirement? If you can use a different format, protobuf-net supports merging fragments into existing instances, as simply as:
Serializer.Merge(source, obj);
I think you're on the right track with the Reflection idea.
Since you probably have a wrapper around the XML operations anyway, you could take in the destination object, do the deserialization normally into a new object, then do something similar to cloning by copying over one by one only the properties holding non-default values.
It shouldn't be that complex to implement this, and it would look to consumers from the rest of your application just like in-place deserialization.
I hit the same problem a few weeks ago.
I put a method Deserialize(string serialized form) in the ISelfSerializable interface that an entity class of mine implemented. I also made sure the interface forced the class to have a default constructor.
In my factory I created an object of that type and then deserialized the string into it.
This is not thread safe thing to do... But you can do:
[Serializable]
public class c_Settings
{
static c_Settings Default;
public static SetExistingObject(c_Settings def)
{
Default = def;
}
public string Prop1;
public bool Prop2;
public c_Settings()
{
if (Default == null)
return;
MemberInfo[] members = FormatterServices.GetSerializableMembers(typeof(c_Settings));
FormatterServices.PopulateObjectMembers(this, members, FormatterServices.GetObjectData(Default, members));
}
}
This way you feed your object to deserialiser and deserialiser only overwrites whatever is written in .xml.

Categories