前言
作为一个程序员,你的相当一部分时间可能会用在调试。不知道大家是否同意,异常处理(Exception Handling)是一个看似简单,但是又极难做好的工作。当然,现在已经有一些业界经验以及框架(例如Enterprise Library中的Exception Handling Application Block)可供参考和使用,这些框架可以帮助我们较为灵活地配置,处理或者记录异常。我今天要跟大家分享的一个话题是,如何在记录异常的时候,包含源代码文件名和行号等有用信息。如果有这些信息,我们将能更加简单地定位到问题所在。
案例演示
为了讲解这个内容,我准备了一个简单的项目来做演示,如下所示
实际上,这个Solution中有两个项目,一个是作为组件的ClassLibrarySample
1: using System;
2:
3: namespace ClassLibrarySample
4: {
5: public class Test
6: {
7: public void MyMethod(int a, int b) {
8: try
9: {
10: Console.WriteLine(b/a);
11: }
12: catch (Exception ex)
13: {
14: Console.WriteLine(ex.Message);
15: }
16: }
17: }
18: }
另一个是作为调用程序的ConsoleApplicationSample
1: using System;
2:
3: namespace ConsoleApplicationSample
4: {
5: class Program
6: {
7: static void Main(string[] args)
8: {
9: var t = new ClassLibrarySample.Test();
10: t.MyMethod(0, 1);//这个调用会出错,因为会发生除零错误
11: Console.Read();
12: }
13: }
14: }
这个程序运行起来肯定就是会报告异常,然后被捕捉到,我们在主程序上面可以看到如下的输出
我们都知道,这样的异常消息可能对我们帮助不是很大,尤其是如果源文件中代码有成百上千行,那么如果不能快速定位到可能是哪一行出了这个异常,那么看起来调试和排错都会很难。
那么是否有办法在异常消息中,得到源代码文件的一些信息呢?事实上是可以做到的,你只要像下面这样修改即可:使用了StackTrace这个类型
1: using System;
2: using System.Diagnostics;
3:
4: namespace ClassLibrarySample
5: {
6: public class Test
7: {
8: public void MyMethod(int a, int b) {
9: try
10: {
11: Console.WriteLine(b/a);
12: }
13: catch (Exception ex)
14: {
15: Console.WriteLine(ex.Message);
16: //通过如下代码来记录异常详细的信息
17: var trace = new StackTrace(ex, true).GetFrame(0);
18: Console.WriteLine("文件名:{0},行号:{1},列号:{2}", trace.GetFileName(), trace.GetFileLineNumber(), trace.GetFileColumnNumber());
19: }
20: }
21: }
22: }
这样一来,我们再进行调试的时候,就可以看到更加详细的信息了。
大家可能会很好奇,这个信息是怎么给我们的呢?其实,要想实现这个功能,必须满足一个前提条件,就是必须有ClassLibrarySample这个组件对应的调试符号文件(pdb)。
如果我将这个文件删除掉,会怎么样呢?
我们看到,如果没有pdb文件,则输出的信息是空白的。
所以,如果你想使用这个技术来记录这些与源代码有关的详细信息,需要确保在部署应用程序的时候,将有关组件的pdb文件也一起部署。
如果是私有部署的话,那么要做到这一点是不难的,打包的时候,将pdb文件一起包含进去就可以了。但如果这个组件是公有部署(部署到GAC) 的话,就需要额外的一些步骤。
为了将程序集部署到GAC,我们首先需要对其进行强名称签名。
然后,通过gacutil这个命令行工具,可以手工地将其添加到GAC中
接下来,为了让主程序使用GAC中这个组件,而不是程序根目录下面的那个。我们需要对引用做一个设置:Copy local设置为false
再次运行主程序的话,我们会得到如下的输出
还是没有与源代码有关的详细信息,这是因为注册到GAC的程序集默认都是没有pdb文件的。他们一般在下面这样的目录里面
【备注】.NET Framework 4.0这个版本中对于GAC的路径做了调整,不再是原先的c:\windows\assembly目录了
所以,如果需要的话,你可以将pdb文件,手工(或者通过脚本)复制到这个目录,例如
这样的话,就可以在运行主程序的时候,得到与源代码有关的详细信息了。