我的应用程序试图反序列化客户端发送的数据,但失败时出现了以下错误:
引发的异常:'System.Runtime.Serialization.SerializationException‘in mscorlib.dll 附加信息:无法获得成员‘<..ctor>b_0’。
谷歌没有给出结果。好的,我决定进入反序列化逻辑,试图找出到底是什么导致了这一点。好吧,一天过去了,我离得很远。
我使用Microsoft参考源网站的说明来配置Visual。它确实下载了一些东西
MicrosoftPublicSymbols\mscorlib.pdb\
DCF1E4D31F6944AC87E7A634262BEE881\mscorlib.pdb (780kb)
E47257B512BA49BC9FC367C532FC5F1E2\mscorlib.pdb (953kb)但是调试器不会介入。
我搜索了更多,并找到了另一种方法-安装了dotTrace应用程序和用作源服务器。这也于事无补。我仍然看到以下情况:

Symbol Load Information弹出mscorlib.pdb说
加载C:\Users\me\AppData\Local\Temp\SymbolCache\MicrosoftPublicSymbols\mscorlib.pdb\e47257b512ba49bc9fc367c532fc5f1e2\mscorlib.pdb:符号。
我可以进入System.Windows.Forms、System.Linq等--所以一般来说,它是有效的--它只是对BinaryFormatter.Deserialize()的特定调用不起作用。这样做的原因是什么,我怎样才能让它介入呢?
可能是因为SecuritySafeCritical属性吗?
[System.Security.SecuritySafeCritical]
public Object Deserialize(Stream serializationStream)我使用的是VS 2015 .Net 4.5.2 (尽管我尝试了4.5的结果)。
发布于 2015-10-29 19:38:48
没有任何细节,我可以假设这是与您试图序列化和反序列化的对象的版本之间的兼容性问题。看起来客户端向您发送一些旧的对象位(构造函数中没有lambda )。和您的服务器运行较新版本的软件搜索某些lambda方法。
<.ctor>b__0 -是.ctor (对象构造函数)中第一个lambda方法的方法名。
因此,例如,如果在客户端的机器对象A上有:
class A {
public A() {
int a = 5;
int b = 7;
// Plain code, no lambdas
}
}然后在服务器上更新类,在构造函数中引入lambda:
class A {
public A() {
int a = 5;
int b = 7;
Func<int,int> some = x => x * 2 + a;
}
}在此之后,它们的二进制表示不一样,服务器版本的A中有私有的不可见方法<.ctor>b__0。

发布于 2015-11-12 05:22:00
微软并不会上传每个mscorlib.dll更新的源代码,这就是为什么您只能获得公共PDB而没有任何源数据的原因。但是有一个来自雷德盖特反射器的Visual插件,您可以在那里使用反编译第三方DLL并在VS调试器中遍历它们。


来自Jetbrains的DotPeek也允许支持符号服务器的PDB生成和托管进行调试。
也许这有助于您调试问题。
发布于 2016-11-24 07:39:54
tl;dr:编译器的不同版本(或不同的设置?)可以为对应于匿名函数的生成方法生成不同的名称。如果序列化类的私有字段指向这样的方法,则会得到异常,即使源在两个构建之间没有更改。
我只是跟踪了确切的情况类型,但使用了在asp.net应用程序的会话中触发的反序列化。就像这种情况一样,我们使用了BinaryFormatter。
<.ctor>b__0对应于与匿名函数对应的生成方法。
现在,这里的问题是序列化过程中对这样一个方法的依赖,因为在不同的构建中,名称不能保证是相同的(即使源代码没有变化)。这几乎可以肯定地追溯到序列化类的私有实例字段中的某种委托。请注意,声明匿名函数的类不一定是在私有字段中保存对该函数的引用的类。
不幸的是,我没有时间跟踪为什么相同的源为匿名函数生成不同的名称,但考虑到所涉项目的历史,它要么是传递给它的选项的不同编译器版本。我相信这是更早的。
如果您可以访问两侧的程序集,则可以确认更改。首先,我尝试在DotPeek中导出这两个程序集的删除源,然后对文件夹进行区分。这并不是一个很好的过程,但这可能是由于一些需要设置的DotPeek设置所致。
更有效的方法是将非依赖型和反射器结合起来。可以对前面的程序集进行比较。我这样做的方法是更改查询中的一个构建,以获得所有序列化类的构造函数,这些构造函数都有任何类型的更改。这将它缩小到了几个类/构造函数(如果匿名函数是在一个不可序列化的类中创建的,那么就有可能无法以这种方式捕获它)。
有一次,我把它归结为几个构造函数,从n依赖性开始,我打开了一个旧的和新的比较,这个比较使用了反射器。这不仅以与异常相同的格式显示了方法名,而且已经显示了在代码库中正确的方法名。
一旦我新建了这个类,我发现最好是在一个单独的resharper窗口中打开每个程序集,并查看类的方法。它在那里很明显。
还请注意,在代码被更改的情况下,即使是相同的编译器版本/选项也可能给出不同的名称,因此在指向函数的可序列化类中拥有私有字段是非常脆弱的。下面的答案将在此基础上扩展:https://stackoverflow.com/a/1133465/66372
https://stackoverflow.com/questions/33419067
复制相似问题