客户生产环境上轻量级调试方法

分享到:

2013-10-16 12:16:28

解决客户支持问题是让我我们很头痛的事情,因为我们没办法在客户机器上调试,一般都是

打日志。日志看不出问题的话,甚至要在本机装个旧版U8,再把客户数据搞过来在本机调试。

   花费了大量宝贵时间来准备调试环境,浪费时间浪费生命,还耽误客户的使用,甚至有时面

对客户的紧急问题我们素手无策。

  另外基本上我们每周都会有支持问题,假设我们每周浪费半天的时间,每个月4周,一年12

个月,就浪费24天,一个多月的时间。整个部门几十个人算下来就是几十个月。要是整个公司

算下来更可怕。

  假设能有一种方法能在客户机上直接调试,省去了在本机准备调试环境的时间,那是多么幸

福的事情啊。本文就提供了这样的解决方案,能够节约时间,提高支持问题解决效率,提高客

户满意度,希望对大家有所帮助。

   下面以一个实际的例子讲解一下具体的过程。大致分为三个步骤,部署环境、编译和调试:

  第一步部署环境

      客户机上一般都只会安装.NETFramework3.5不会装4.0,我们编译的时候只能使用.NET3.5的编译器。如果我们的代码中使用了.NET4.0的新特性(如动态类型,默认参数等),这些特性是需要.NET4.0的编译器支持的,因此是无法通过编译的。另外MsBuild需要依赖WindowsSDK(安装VisualStudio的时候会自动安装WindowsSDK),我们没必要在客户机安装体积庞大的VisualStudio,只需要从本机拷贝WindowsSDK到客户机,这里面有我们需要的编译和调试程序。只拷贝bin目录即可,如下图:

 

我们将其拷贝到客户机对应目录,如下图:

 

然后修改注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v6.0AInstallationFolder属性值指向该目录即可。如果该注册表项不存在添加一个就行。

 

当然也可以将WindowsSDK拷贝到其他目录,只需修改上面的注册表值使其指向该目录即可。

  第二步使用MsBuild在客户机上编译项目

  目的是产生程序集文件和符号文件(pdb文件),没有符号文件是不能调试的。

  将我们的源代码拷贝到客户机,这里我使用的是UAPUFIDA.U8.UAP.UI.Runtime.List项目,

如下图:

 

如果客户将U8装在C盘,我们需要将

UFIDA.U8.UAP.UI.Runtime.List_mao.csprojUFIDA.U8.UAP.UI.Runtime.List_mao.csproj.user中的

DLL引用路径修改为C盘。否则会找不到引用的DLL导致编译失败。

接下就可以使用 MsBuild编译了,MsBuild的使用很简单 只需将项目文件名作为参数传入即可

如下图:

 

绿色的 Build successded表示我们编译成功了。将生成的DLL,和PDB(F:\UFIDA.U8.UAP.UI.Runtime.List\bin\Debug目录)文件拷贝到C:\U8SOFT\UAP\Runtime目录。

至此,编译工作结束了。

  第三步使用调试器调试。我们都知道著名的非托管调试器WinDbg, WinDbg虽然强大但是使用起来很复杂,并且在调试时不能显示C#代码,顶多只能显示IL代码,不够直观。其实在

windowsSDK中有一个简单实用的调试器Mdbg.exe(C:\Program Files\Microsoft

SDKs\Windows\v7.0A\bin\Mdbg.exe),可以在调试时显示C#代码。我们启动它,如下图

 

 

启动我们的U8门户程序EnterprisePortal.exe,并打开单据列表

 

运行a命令,列出所有进程

 

可以看到EnterprisePortal.exe的进程ID2372.

使用命令 a将调试器附件到进程上。

mdbg> a 2372

设置符号路径

 [p#:0, t#:11] mdbg> sy path C:\U8SOFT\UAP\Runtime

Current symbol path: C:\U8SOFT\UAP\Runtime

在行双击事件上设置断点   

[p#:0, t#:11] mdbg> b UFIDA.U8.UAP.UI.Runtime.List!UFIDA.U8.UAP.UI.Runtime.List.

UI.BaseUIEventHandler.ProcessDBClickEvent

Breakpoint #2 bound (UFIDA.U8.UAP.UI.Runtime.List!UFIDA.U8.UAP.UI.Runtime.List.U

I.BaseUIEventHandler::ProcessDBClickEvent(+0))

设置断点的命令格式是 b modulename!namespace.class.methodname

断点已打上.输入"g" 继续运行,点击某行按钮触发ProcessDBClickEvent事件,断点被触发,断点在大括号处,

输入"s" 继续执行到下一行.

查看堆栈中的变量: 可使用 print args 打印 args.

[p#:0, t#:0] mdbg> print args

args=System.Data.DataRow

       _table=System.Data.DataTable

       _columns=System.Data.DataColumnCollection

       oldRecord=0

       newRecord=0

       tempRecord=-1

       _rowID=1

       _action=System.Data.DataRowAction

       inChangingEvent=False

       inDeletingEvent=False

       inCascade=False

       _lastChangedColumn=<null>

       _countColumnChange=0

       error=<null>

       _element=<null>

       _rbTreeNodeId=1

       _objectTypeCount=9473

       ObjectID=9191

可以使用sh 命令显示源代码, *表示,当前代码执行到的地方.

[p#:0, t#:0] mdbg> sh

753                 return;

754             }

755

756:*            string menuID = "", subSysID = "", voucherName = "", authID = "

",

757                 voucherIDColName = "", voucherDetailIDColName = "", cardNum

 = "", voucherType = "", instance = "";

758             VoucherTypeEnum voucherTypeEnum = VoucherTypeEnum.UAPVoucher;

[p#:0, t#:0] mdbg>

Sh 20 可以显示当前光标上下20行的代码。

使用?命令或help可以查看帮助。Mdbg调试器命令的列表在文章的最后给出。

至此,已经能够开始在客户机上调试问题了。

很神奇吧,终于可以摆脱庞大笨拙的VisualStudio了。

 

 

    还没有结束,下面介绍一个更好用的工具,著名的.net开源IDE SharpDevelop

功能和VIsualStudio基本一样,但是体积只有14M。如果客户机允许我们安装软件,那么使用SharpDevelop是更好的选择。最新的4.1版本已经支持.NETFramework4.0

. NETFramework 3.5对应的版本是3.2,为了在客户机使用我们还是安装3.2版本的。

SharpDevelop也是需要依赖WindowsSDK的,所以前面讲的第一步的配置工作是不可少的。接下来的编译和调试与使用VIsualStudio一样,大家都轻车熟路,不详细讲了,只给一个调试时的截图。具体的大家用用就知道了。

 

SharpDevelop 大家可以到网上下载。

 

Mdbg.exe命令列表

 

命令

说明

ap[rocess] [number]

切换到另一个调试的进程或打印可用进程。number 不是真正的 PID,而是一个从 0 开始索引的列表。

a[ttach] [pid]

附加到进程或打印可用进程。

b[reak] [ClassName.Method | FileName:LineNo]

在指定方法处设置断点。按顺序对各个模块进行扫描。breakFileName:LineNo用于在源代码中的某个位置设置断点;break~number用于在当前使用x命令显示的符号处设置断点;breakmodule!ClassName.Method+IlOffset用于在完全限定位置设置断点。

ca[tch] [exceptionType]

让调试器在遇到所有异常时都中断,而不仅是在遇到未处理的异常时中断。

conf[ig] [option value]

显示所有可配置选项,并显示在不提供任何可选值的情况下如何调用选项。如果指定了选项,请将value设置为当前选项。

当前可用选项有:

extpath:设置路径,使用load命令时在该路径中搜索扩展。

extpath+:向现有路径中添加路径,可以从这些现有路径加载扩展。

del[ete]

删除断点。

de[tach]

与调试的进程分离。

d[own] [frames]

下移活动堆栈帧。

echo

向控制台回显消息。

ex[it] [exitcode]

退出 MDbg.exe 外壳程序,可以选择指定进程退出代码。

fo[reach] [OtherCommand]

对所有线程执行命令。OtherCommand是对一个线程执行的有效命令;foreachOtherCommand则对所有线程执行同一命令。

f[unceva l] [-ad Num] functionName [args ... ]

对当前活动线程进行函数求值,其中,要求值的函数为functionName。函数名必须完全限定,包括命名空间。

-ad选项指定用于解析函数的应用程序域。如果未指定-ad选项,则用于解析的应用程序域默认为用于函数求值的线程所在的应用程序域。

如果要进行求值的函数不是静态的,则传入的第一个参数应为this指针。在所有应用程序域中搜索函数求值所需的参数。

若要从应用程序域中请求值,请在变量前使用模块名和应用程序域名作为前缀。例如funceva l -ad 0 System.Object.ToString hello.exe#0!MyClass.g_rootRef

此命令在应用程序域0中对函数System.Object.ToString进行求值。由于ToString方法为实例函数,因此,第一个参数必须为this指针。

g[o]

让程序继续执行,直至遇到断点、程序退出代码或导致程序停止的事件(例如,未处理的异常)。

h[elp] [command]

或者

? [command]

显示所有命令的说明或对指定命令的详细说明。

ig[nore] [event]

让调试器仅在遇到未处理的异常时停止。

int[ercept] FrameNumber

将调试器回滚到指定的帧号码。

如果调试器遇到异常,使用此命令可以将调试器回滚到指定的帧号码。可以使用set命令更改程序状态,然后使用go命令继续。

k[ill]

停止活动进程。

l[ist] [modules|appdomains|assemblies]

显示已加载的模块、应用程序域或程序集。

lo[ad] assemblyName

按以下方式加载扩展:加载指定的程序集,然后尝试从Microsoft.Tools.Mdbg.Extension.Extension类型运行静态方法LoadExtension

mo[de] [option _disibledevent="font-family:Calibri;font-size:small;">                                                              

声明:此篇为用友服务中心文章,转载请标明出处链接:
  • 相关文章
  • 热门下载
  • 数据修复
  • 热门标签
合作伙伴