第五章 - 代码调试
调试是一种技术,它可以逐步执行应用程序的代码以帮助开发人员分析和理解其数据和行为,从而跟踪和纠正错误及漏洞。
SnapDevelop 提供了全面而强大的调试工具,使开发人员能够调试桌面应用程序、Web API、甚至是通过 Docker 或 Kubernetes 调试将应用部署到 Docker 容器或 Kubernetes 集群中再调试,以使调试环境更接近生产环境。
通过阅读本文,您将了解 SnapDevelop 的调试工具以及如何使用这些工具来跟踪应用程序中的错误。
创建项目
您将从创建一个 Web API 模板项目开始,这样只需对代码进行最少的更改。
从主页中单击 新建 按钮。
或者通过 文件 > 新建 > 新建项目 菜单创建一个新项目。
选择 ASP.NET Core Web API,然后单击 下一步。
指定项目的名称和位置,并单击 下一步。
取消勾选 启用 OpenAPI 支持 (以便不生成 Swagger 页面),其余选项保留默认设置。点击 创建。
关于该页面设置的详细说明,请参考 快速搭建 Web API 工程(EFCore 类型)。
在 解决方案资源管理器 中打开 ExampleWebApplication > Controllers > WeatherForecastController.cs 文件。
将这部分代码:
替换为以下代码:
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
var WeekWeather = new List<WeatherForecast>();
for (int i = 0; i < 7; i++)
{
WeekWeather.Add(GetRandomWeather(i));
}
return WeekWeather.ToList();
}
public WeatherForecast GetRandomWeather(int day)
{
var randSummary = Summaries[Random.Shared.Next(Summaries.Length)];
return new WeatherForecast
{
Date = DateTime.Now.AddDays(day),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = randSummary
};
}
点击工具栏上的运行图标()。应用程序的服务将启动;Web 浏览器将访问 Web API 并显示以下数据。
添加断点
断点 是最基本也是最重要的调试技术之一。断点 用来告诉调试器在何处暂停代码的执行,以便您可以查看变量的值、内存的行为、或某些代码是否已执行。
当您知道要在运行时详细检查的代码行或代码片段时,您可以在此代码行或段插入断点。例如,在 WeatherForecastController.cs 文件中将光标放在第 24 行(带有 var WeekWeather = ...
语句的行),然后添加一个断点。
添加断点有 3 种方式:
- 右键菜单 -- 在要设置断点的代码行上,右键单击然后选择 断点 > 插入断点。
- 调试菜单 - 将光标放在要添加断点的代码行上,然后选择菜单 调试 > 切换断点:
- 断点栏 -- 在要设置断点的代码行上,单击行号栏左侧的灰色条:
当代码行设置了断点时,断点栏将会显示一个红点,代码行的文本背景也会变成红色:
用同样的方法在第 37 行(带有 var randSummary = ...
语句的行)也添加一个断点。
删除或禁用断点
如果代码行没有设置断点,将光标放在行上,然后选择菜单 调试 > 切换断点 (或按F9
键)将会插入断点;如果代码行已有断点,执行相同操作则会去掉断点。或者直接点击断点栏的红点也可以去掉断点。
如果要禁用断点,请右键点击插入了断点的代码,然后选择 断点 > 禁用断点(或者将鼠标悬停在断点栏的红点上,然后从弹出的图标中选择 禁用断点 )。被禁用后,红点将变为红色圆圈。
启动调试器
要开始调试项目,您可以使用 调试 > 开始调试 菜单(或按 F5 )。
或者点击工具栏上的按钮。按钮的名称将根据调试设置而改变。
调试器将启动应用程序并附加到应用程序进程中。
开始调试后,应用程序的控制台窗口将打开;Web 浏览器将运行并访问 Web API。
页面将显示空白,因为调试器触发断点并暂停应用程序的执行。焦点将返回到 SnapDevelop IDE。
使用调试器
当您开始调试应用程序时,SnapDevelop 的 IDE 将自动更改为调试模式。当触发断点时,调试器会暂停。您可以在 IDE 中通过代码编辑器、菜单、工具栏、或调试窗口获取当前执行代码的详细信息。
编辑器
当前行标识
当调试器触发断点暂停应用程序执行时,断点栏的当前断点的图标位置将显示一个黄色箭头()(在下图中,该图标和断点图标叠加在一起了),以及接下来要执行的代码行的文本背景将变为黄色(表示代码尚未执行)。
数据提示
当调试器触发断点暂停应用程序执行以后,您不仅可以控制代码的执行,还可以在代码编辑器中查看数据提示。您可以将鼠标悬停在变量或参数上检查变量的名称和值。数据提示仅在中断模式下出现,并且仅出现在当前执行范围内的变量上。
例如,单击工具栏上的 逐语句 或 逐过程 按钮可以让程序执行当前代码并移至下一行或下一方法。 这些按钮将在 菜单 中更详细地解释。
点击 逐语句,然后将鼠标悬停在 WeekWeather
变量上以显示数据提示:
数据提示显示元素的标识符及其运行时类型。当元素为复杂类型时,可以单击或悬停在左侧的三角图标上来展开查看更多信息。当无法获取变量的当前值时,数据提示上会出现警告标志。
对于字符串类型的变量值,您还可以点击变量值后面的放大镜图标,然后选择在 JSON 可视化工具、HTML 可视化工具、或文本可视化工具中查看变量值。
菜单
当调试器触发断点时,调试 菜单会显示以下子菜单:
菜单 | 描述 |
---|---|
窗口 | 包含了一系列可以执行不同调试任务的窗口列表。这些窗口将在 窗口 小节中更详细地描述。 |
继续 | 继续执行直到下一个断点(或异常)。 |
中断全部 | 停止代码的执行,并尝试打开它中断执行的相应源代码文件。 |
停止调试 | 终止调试会话并关闭应用程序。 |
附加到进程 | 尝试将调试器附加到已经运行的进程。只有当进程具有可加载的调试信息时该功能才有效。 |
切换断点 | 切换当前行中的断点。 |
删除所有断点 | 删除所有断点(无法撤销)。 |
禁用所有断点 | 禁用所有断点(可以撤销)。禁用的断点不会生效,也就是不会中断代码执行。 |
<项目名称> 属性 | 打开当前项目的调试属性。详情请参阅 调试。 |
逐过程 | 执行当前语句,但如果是一个函数则不进入其中。 |
逐语句 | 如果是一个函数(并且其调试信息可用),则执行当前语句并进入函数。 |
跳出 | 执行当前作用域内的其余代码,并返回到调用当前函数的位置。 |
非调试模式下的 调试 菜单会显示不同的子菜单。大部分与调试模式下的子菜单相同,下面只描述不同的子菜单:
菜单 | 描述 |
---|---|
开始调试 | 开始调试当前项目。 |
不调试启动 | 在不附加调试器的情况下启动当前项目。 |
工具栏
处于调试状态下的 IDE 将显示一个调试工具栏,以便快速启动、停止调试、或者在代码中导航。
按钮 | 描述 |
---|---|
中断全部 | 暂停应用程序执行并尝试打开当前正在执行的文件。 |
停止 | 终止调试会话并关闭应用程序。 |
显示下一条语句 | 显示接下来将执行的语句。 |
逐语句 (F11) | 如果是一个函数(并且其调试信息可用),则执行当前语句并进入函数。F11 是一个单步执行命令。它每次推进应用程序执行一个语句,并详细地检查执行流程。默认情况下,调试器会跳过非用户代码。 |
逐过程(F10) | 执行当前语句,但如果是一个函数则不进入其中。F10 跳过应用程序代码中的方法或函数,但仍会执行代码块。 |
跳出(Shift + F11) | 执行当前作用域内的其余代码,并返回到调用当前函数的位置。 |
进程 | 下拉列表将显示调试的进程。当有多个项目同时开启了调试器时,您可以从列表中自由切换进程进行调试。 |
窗口
接下来将描述各种调试窗口。当调试器触发断点时,您可以从菜单 调试 > 窗口 打开一系列相关的窗口来帮助您调试,包括:断点、异常设置、监视、自动窗口、局部变量、调用堆栈、和 线程。在 断点、监视、局部变量、调用堆栈 等窗口中,您可以选择列表中多个(按 Shift 键选择)或所有项(从右键菜单选择 全选),然后进行复制、编辑、添加监视等操作。
自动窗口
自动窗口 窗口显示当前语句以及前一语句中的变量和值。
对于复杂的值,可以展开查看其成员。
字符串可视化工具
在 自动窗口、局部变量、监视 等窗口中,查看字符串类型的变量值时,您可以点击变量值后面的放大镜图标,然后选择在 JSON 可视化工具、HTML 可视化工具、或文本可视化工具中查看变量值。字符串将被转换为 JSON、HTML、或 TXT 格式显示。
局部变量
局部变量 窗口显示在局部范围(通常是当前函数或方法)内定义的变量。
对于复杂的值,可以展开查看其成员。
对于字符串类型的变量值,您可以点击变量值后面的放大镜图标,然后选择在 JSON 可视化工具、HTML 可视化工具、或文本可视化工具中查看变量值。
由于本案例非常简单,所以该窗口显示的变量跟自动窗口的变量相同。
监视
监视 窗口可以观察变量或表达式的值。该窗口可以一次观察多个变量。将变量添加到监视窗口后,您可以在运行调试器时看到它的值发生变化。与其他变量窗口不同,监视 窗口始终显示您正在监视的变量。
要添加监视,请双击 添加要监视的项 字段(或右键点击然后选择相应的菜单)并输入要跟踪的变量或表达式的名称。表达式的语法与 C# 表达式相同。
您还可以在 自动窗口 或 局部变量 窗口中将变量添加到监视窗口(从右键菜单中选择 添加监视 )。
此外,也可以在代码编辑器中将变量添加到监视窗口(选中变量,从右键菜单中选择 添加监视 )。
快速监视
快速监视 窗口跟 监视 窗口类似,不同的是 监视 可以同时显示多个变量的情况,快速监视 每次只显示一个变量或者表达式。
快速监视 窗口不能从 调试 > 窗口 菜单中打开。要打开 快速监视 窗口,您必须得右键点击变量或表达式,然后选择 快速监视。
调用堆栈
调用堆栈 窗口显示了方法和函数的调用顺序。它可用于检查和理解程序的执行流程。
第一行显示的是当前方法,第二行显示的是调用当前方法的方法,依此类推。没有调试信息的代码被列为 外部代码。要显示这些代码,请右键单击然后选择 显示外部代码。
双击调用堆栈窗口中的方法将在代码编辑器中打开定义该方法的代码文件。
线程
线程 窗口显示当前程序正在运行的线程,以及当前被暂停的线程。
列描述如下:
列 | 描述 |
---|---|
旗帜 | 用来标记那些需要特别注意或特别重要的线程,选中后显示红色旗帜。您可以点击工具栏的 仅显示标记的线程 图标来只查看标记了的线程。 |
ID | 线程的 ID。 |
托管 ID | 托管线程的 ID。 |
类别 | 线程的类别。通常是用户界面线程、远程过程调用处理程序、工作线程。(对于当前版本无法识别的线程类别将显示为 未知线程。) |
名称 | 线程的名称,如果有的话。 |
位置 | 线程运行的位置。双击它将显示完整的调用堆栈。 |
优先级 | 显示系统分配的线程的优先级。 |
关联掩码 | 确定线程可以在哪些处理器上运行。 |
进程 ID | 进程的 ID。 |
进程名称 | 进程的名称。 |
挂起项计数 | 确定线程是否可以运行。 |
传输限定符 | 调试器连接到的机器的 ID。 |
断点
断点 窗口显示当前项目上的所有断点、它们的位置及其设置。
按钮说明如下:
图标或文字 | 描述 |
---|---|
删除选定的断点。 | |
删除满足当前搜索条件的所有断点。 | |
禁用或启用满足当前搜索条件的所有断点。 | |
转到源代码。 | |
显示列 | 选择显示哪些列。 |
搜索 | 输入搜索条件。 |
在列中 | 与搜索一起使用,指定在哪些列中进行搜索。 |
重置所有搜索条件以显示所有断点。 |
断点设置
右键单击断点然后选择 设置 以打开断点设置:
位置 -- 显示断点所在的位置。
条件 -- 您可以指定一个或多个条件,只有当条件满足时,断点才会被触发并暂停调试器。
您可以指定两类条件:
条件表达式 -- 每次执行断点上的代码时都会评估的 C# 表达式。此表达式的范围为设置了断点的行。
命中计数 -- 检查当前行被执行的次数。您可以选择以下运算符:
=
、数倍于
和>=
。
输入条件后需要按 回车 键保存条件设置。
如图所示,现在断点只会在 index
变量值为 5 时触发。
带有条件的断点的图标中间将带有加号。
点 确定 关闭 断点设置 窗口。
异常设置
异常设置 窗口允许您选择哪些异常发生时调试器应中断执行。异常将按照类型进行显示。您可以在列表中展开一个异常类型的节点(目前只有Common Language Runtime Exceptions 节点),然后选中其中一个异常的复选框来启用该异常。您还可以通过选择类型节点的复选框来选中其下的所有异常。当异常的复选框被选中后,则无论该异常是否已处理,调试器都会在抛出异常的地方中断执行。
该窗口提供以下操作:
按钮 | 描述 |
---|---|
仅显示已启用的异常。列表中将只显示已经启用的异常。 | |
将一个异常添加到选定类别。 | |
从列表中删除选定异常。 | |
将列表恢复到默认设置。 |
当进入发生未处理异常的代码行时,会出现一个 未处理的异常 窗口(如下图)。点击 查看详细信息 后,将打开 快速监视 窗口。
多进程调试
您可以选中一个项目,然后选择 调试 > 开始调试 菜单;然后继续选中第二个项目,选择 调试 > 开始调试 菜单。当有两个或以上项目同时开启调试时,调试器将自动进入多进程模式。这时,您可以通过工具栏的 进程 下拉列表切换当前调试的项目。
当选择 停止调试 时,将同时停止所有项目的调试。
附加到进程
您可以将调试器附加到已运行的进程来调试进程。您可以调试本地或远程机器上正在运行的应用程序、同时调试多个进程、调试不是在 SnapDevelop 中创建的应用程序,或者调试不是从 SnapDevelop 中启动的任何应用程序。
为了使用调试器的所有功能,调试器要能加载进程的调试信息。
单击调试工具栏中的 停止 按钮()来停止调试会话。
然后点击调试工具栏中 不调试启动 按钮()(或者选择菜单 调试 > 不调试启动 )来只启动(而不调试)应用程序。
然后选择菜单 调试 > 附加到进程。
附加到进程 窗口将显示。此窗口具有以下字段:
字段 | 描述 |
---|---|
连接类型 | 调试器连接类型。Default 指的是本地操作系统调试器实现。 |
连接目标 | 连接目标。如果连接类型是 Default,则指的是要连接的机器,通常为计算机名称。 |
可用进程 | 筛选进程列表。 |
附加到进程 窗口列出了可能附加到的进程(可以点击窗口底部的 刷新 按钮来查看当前进程列表)。请记住,并非所有进程都可以调试,因为有些进程可能没有可用的调试信息。
在进程列表中选择 ExampleWebApplication 进程(或您的项目的名称)并单击 附加到。
调试器将被附加到进程。您可以在浏览器中重新访问 http://localhost:5000/weatherforecast,在执行到设置了断点的代码行时,调试器将暂停应用程序的执行并将焦点返回到 SnapDevelop IDE 中。
在 Docker 或 Kubernetes 环境中调试项目
在 Docker 或 Kubernetes 环境中调试项目,意味着在开发和测试阶段的任何时候,您都可以选择在 Docker 或 Kubernetes 上调试项目,以确保程序在 Docker 或 Kubernetes 环境中能运行正常。
首先请确保项目中已添加 容器支持、容器编排支持、或 Kubernetes 支持;并且断点已经设置。
只有添加了相应的支持后,才能选择运行配置为 Docker、Kubernetes、或 KubernetesCompose。
配置运行后将自动构建所需的调试镜像和容器。
如果您需要更改运行配置,请单击按钮旁边的箭头然后选择 [项目] 属性。具体操作请参考下一小节。
调试设置
调试设置允许您为解决方案中的项目配置调试配置文件。您可以在解决方案资源管理器中右键点击项目节点然后选择 属性 来访问调试设置,或者在工具栏的运行配置下拉列表中选择 [项目] 属性。目前只为 C# 类型的项目提供了调试设置。
通常,所选的配置文件不同,程序启动方式也会有所不同。具体说明请参考 调试。