How to debug (step into) BinaryFormatter.Deserialize()?

前端 未结 3 1184
长发绾君心
长发绾君心 2020-12-10 17:34

My app tries to deserialize data sent by client and it fails with the following error:

Exception thrown: \'System.Runtime.Serialization.Serializatio

3条回答
  •  清歌不尽
    2020-12-10 18:07

    tl;dr: different version of a compiler (or different settings?) may generate different names for the generated method corresponding to an anonymous function. If such a method is pointed by a private field of a serialized class you get the exception, even though the source didn't change between the 2 builds.


    I just tracked the exact type of situation, but with the deserialization triggered in an asp.net application's session. Like this case, the BinaryFormatter is used.

    <.ctor>b__0 corresponds to the generated method corresponding to an anonymous function.

    Now, the problem here is the dependency on such a method during serialization, because the name is not guaranteed to be the same over different builds (even with an unchanged source). This almost surely tracks to some kind of delegate in a private instance field of a serialized class. Note that such the class where the anonymous function is declared is not necessarily the class that holds the reference to that function in a private field.

    Unfortunately I didn't have time to track why the same source produces different names for the anonymous function, but given the history of the project involved it is either a different compiler version of the options passed to it. I am convinced it is the earlier.

    If you have access to the assemblies in both sides, you can confirm the change. At first I tried exporting the dissembled source of both assemblies in DotPeek and then doing a diff of the folders. That didn't prove a good process, but it may be due to some DotPeek settings that need to be set or something.

    What worked better was using a combination of ndepend and reflector. You can do an assembly comparison of the earlier. The way I did it was to change one of the build in queries to get all constructors of serialized classes that had any kind of change. This narrowed it down to a few classes/constructors (there is a risk of not catching it this way, if the anonymous function was created in a non serializable class).

    Once I had it down to a few constructors, from ndepend I opened an old vs new comparison that uses reflector for it. This not only showed the method name in the same format as the exception, but already showed got me to the right one in the code base.

    Once I new the class, I found it better to open each assembly in a separate resharper window and see the methods of the class. It is quite visible there.

    Also note that in the case where the code is changed, even the same compiler version/option may give you different names, so it is very brittle to have private fields in serializable classes that point to functions. The following answer expands on it: https://stackoverflow.com/a/1133465/66372

提交回复
热议问题