C#调试含有源代码的动态链接库遇见there is no source code available for the current location提示时的解决方案:
1.首先试最常规的方法:Clean and then rebuild solution,但是没有解决
2.进入Tools>Options,选择Debugging>General 却掉 Enable address-level debugging 选项,在去掉 Require source files to exactly match the original version.
Okay,解决问题。
最近在维护一个项目的时候有这样一个问题,项目Solution A引用了第三方的DLL文件,而我现在需要使用DLL类库的一些工具类,但是又没有相关的文档,所以我就需要Debug到DLL中进行调试查看代码的逻辑。开始的时候我想通过.NET Reflector反射出源代码,但是因为一些原因此方法行不通。现在我找到了遗留下来的DLL的源码,但是在另外的一个solution B中,所以现在我想要调试这些源码,要做的就是把源码映射到我们这个项目的DLL中。在介绍方法之前,先简单的说几个概念。PDB文件,DLL文件,源代码CS文件。当我们想调试一个DLL文件的时候,这三者是一个都不能少的。
DLL文件
就是程序在执行的时候,要使用的文件。注意,程序在运行的时候使用的是DLL这种二进制文件,而不是我们自己写的代码,是我们写的代码通过编译出来的DLL文件。
CS源代码
这就是编写的代码,用来生成DLL文件。程序在运行的时候,是根本不需要CS文件的。
PDB文件
当你编译一个project的时候,在bin目录下,伴随着DLL文件,你都会看到一个PDB文件,这个文件是做什么的呢。PDB是Program Database的简称,也成为Symbol File.PDB中存储的信息用来映射.cs文件中的源代码与编译后的DLL文件的对应关系。Debugger,即调试器,会使用这些信息来解析出两方面的信息:在Visual Studio中的呈现出来的源代码中的行号和这一行在DLL中的地址,即当在Visual Studio中的源代码中的某一行设置一个断点后,因为调试时运行的是DLL文件,Debugger需要知道中断在DLL中的某个地方,而PDB中正是记录着行号与这个地址的对应关系。PDB中解析出来的另一个信息是,这个DLL的源代码在哪里。当然如果是自己写的代码,源代码就在project下。但是如果我们引用了第三方的框架,比如说ASP.NET Framework,这时候我们本地根本就没有源代码,这时候PDB中记录了远端server上的代码地址。一句话概括,PDB文件充当了一个DLL与CS源代码之间的桥梁。
现在我们设定一种需求,比如说,我现在想在我的MVC Project中调试ASP.NET MVC Framework中诸如MVCHandler的Process Request方法,现在我们没有源代码,我们没有办法设置断点,即使使用F11 Step By Step调试,到了这种没有源码的代码行的时候,也是会直接跳过的,因为根本就没有地方可去啊。在调试的时候有一种My Code的概念,只有My Code的DLL才可以调试。其实,说白了,My Code的DLL就是有PDB的DLL。我们要调试MVC的DLL,首先就要获取System.web.mvc对应的PDB文件。在Project的调试状态下,点击Debug-->Windows-->Module,会发现System.web.mvc dll是 Cannot find or open the PDB file状态。微软有专门的服务器来提供框架的代码,所以我们可以从服务器上获取pdb文件。然后在Module中右击System.web.mvc一行,选中load pdb from server,会发现PDB会从server中load到本地。如果此时调试MVC代码,会有下图一样的提示。
因为此时Debugger认为你有PDB文件,是My Code,尝试着去调试,但是没有源代码,所以会提示你映射源代码。我们现在需要设置Tools-->Options-->Debugging-->Genral-->Enable Source Server为选中状态,这样,当调试System.web.mvc的时候,会自动从服务器下载源代码到本地。这时候,就可以调试诸如MVCHandler等ASP.NET MVC Framework中的类了。
回到我们最开始的需求,我们现在的情况是,我们的第三方DLL没有可以下载PDB文件的服务器。所以,我们要把源代码solution B中的DLL在build的时候,生成的PDB文件,拷贝到Soution A中,并且在Debug模式下,Moudule中指定第三方DLL的对应PDB的地址。这时候,在调试的时候,Debugger发现这个DLL中没有标记源代码服务器地址,会向上文说到的一样,会提示问你源代码在哪里,这时候你把路径映射到你本地的源代码就可以了。
注意:在第一种情况下,获取System.web.mvc的pdb文件的时候,是Visual Studio根据DLL中的相关信息,向微软的特定的server发出针对于某个pdb文件的请求,并下载的本地。这个过程是很精确的,下载的版本都是一致的,因为dll中都有相关信息记录的。而在第二种情况下,没有sever可供下载,需要人为导入。这个过程需要非常准确,就是说,你solution A中引用的DLL,必须跟你自己导入的PDB完全一致,完全对应,必须是产生DLL的同时产生的PDB.VS编译器有这样一种机制,在编译C#代码并产生PDB的时候,会有一种算法来优化PDB,好像还涉及到时间戳什么的,就是说,即使先后代码完全一致没有变动,在先后两次编译产生的PDB也是不一样的,如果在调试的时候导入的不一致,是不会映射成功的。
引文链接: