How do you identify the field that is causing binary serialization to fail in .NET?
Asked Answered
N

3

7

I am attempting to serialize an object graph in .NET with the following method:

public static byte[] Serialize(object data)
{
    var binary = new BinaryFormatter();
    using (var ms = new MemoryStream()) {
        binary.Serialize(ms, data);
        return ms.ToArray();
    }
}

However, I am running into the following error:

FormatException: Input string was not in a correct format. 
Stack Trace: 
  at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
  at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
  at System.String.System.IConvertible.ToInt32(IFormatProvider provider)
  at System.Convert.ToInt32(Object value, IFormatProvider provider)
  at System.Runtime.Serialization.Formatters.Binary.__BinaryWriter.WriteValue(InternalPrimitiveTypeE code, Object value)
  at System.Runtime.Serialization.Formatters.Binary.__BinaryWriter.WriteMember(NameInfo memberNameInfo, NameInfo typeNameInfo, Object value)
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteKnownValueClass(NameInfo memberNameInfo, NameInfo typeNameInfo, Object data)
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMembers(NameInfo memberNameInfo, NameInfo memberTypeNameInfo, Object memberData, WriteObjectInfo objectInfo, NameInfo typeNameInfo, WriteObjectInfo memberObjectInfo)
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.WriteMemberSetup(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, String memberName, Type memberType, Object memberData, WriteObjectInfo memberObjectInfo)
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo, String[] memberNames, Type[] memberTypes, Object[] memberData, WriteObjectInfo[] memberObjectInfos)
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
  at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
  at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)

Is there a straightforward way to identify which field is producing this error? I could recursively mark the fields in the object graph as NonSerialized to narrow down potential culprits, but as the object graph is quite extensive, this is burdensome and seems unnecessary.

Note that I am not sure why the BinaryFormatter cannot serialize one or more values in the object graph. If the object can be stored in memory at runtime, it is not clear why it cannot be serialized. Could this be a problem with an enum?

Neelyneeoma answered 12/6, 2012 at 19:55 Comment(0)
S
6

Use Windbg. Download it here (select from the installer only the debugger. You do not need to downlad the complete SDK) and start it.

Then use File - Open Executable - and start it. You will break at the exception in the debugger. If not select before you start

Debug - Event Filters - CLR Exception - Enabled

to enable a breakpoint on every managed exception. Then you need to type

.loadby sos clr 
(if you are using .NET 3.5 .loadby sos mscorwks)
.prefer_dml 1
!dso

This will give you a list with the objects which were used by the current thread before it did fail. Then you click on one of the blue underlined NameInfo instances to see which at which member variable the serializer did fail. I agree that it requires some patience to learn but you can debug such stuff in record time where others need to fiddle around in their code to nail the issue. All you need to do is to look into the NameInfo instance which did cause the issue.

Spiny answered 12/6, 2012 at 20:27 Comment(2)
Sorry for the long delay in accepting this. I never got time to verify this approach, but since it provides insight into a potentially useful tool that I was not aware of, I think this answer is the most useful/promising.Neelyneeoma
I have used this to debug a big change to the data model being serialized and it quickly pointed me in the right direction. Once you have a break in the correct exception, you can use !clrstack -p to get a dump of the stack trace with pointers to parameters. For my case a lot of them had no data, but further up the stack it contained a pointer to the object being serialized.Ljubljana
I
3

The way that I approached this was to serialize the object to a string and then write the string to a file. You can then look at the serialized string, see where it stopped, and infer from there which element it was that caused the problem.

Isomagnetic answered 12/6, 2012 at 20:3 Comment(1)
Clever...I'll give that a try.Neelyneeoma
C
-1

Comment out all the properties, and serialize the object. Reintroduce them one at a time until the error returns.

This is basic debugging.

The stack trace gives hints though, if there aren't to many types being serialized.

Convenience answered 12/6, 2012 at 20:0 Comment(3)
Yes, this is basic debugging, and perhaps I was not clear in my original question, but I am looking forward an alternative to this approach. The object graph is quite broad and deep and I was hoping for a shortcut.Neelyneeoma
@Neelyneeoma I had a similar issue with a Json serialize. The answer was almost always "The last field/property you added"Convenience
Good point. I'll look in the source history to see if there is an obvious change, but unfortunately I am dealing with a very large object graph that covers many files, so this may take some investigation. Thanks for the suggestions.Neelyneeoma

© 2022 - 2024 — McMap. All rights reserved.