上一篇學會用 F12 之後,我終於可以從:
Controller
↓
Service
↓
Repository / DBService
↓
Database
一路追到真正的程式碼。
但很快又遇到另一個問題。
我找到這個方法了。
可是它「寫在這裡」
不代表程式執行時真的有跑到這裡吧?
尤其改企業專案時,很常發生這種情況:
我明明改了這段程式
↓
重新操作畫面
↓
完全沒反應
這時候我以前第一個反應可能是:
是不是我程式寫錯?
是不是瀏覽器快取?
是不是專案沒重新 Build?
但其實還有一個很基本的問題應該先確認:
這次操作,
到底有沒有執行到我改的這段程式?
這時就要用:
Breakpoint
中斷點
中斷點可以先理解成:
我在程式碼某一行放一個「暫停點」,程式執行到這裡時先停下來給我看。
例如 Controller:
public IActionResult Detail(int id)
{
var model = _userService.GetDetail(id);
return View(model);
}
如果我想確認:
開啟詳細資料頁時
到底有沒有進到 Detail()
就可以在:
var model = _userService.GetDetail(id);
這一行下中斷點:

接著執行程式,再去瀏覽器操作詳細資料頁。
如果 Visual Studio 停在這一行:
代表真的有執行到這裡
如果完全沒有停:
那我就要重新確認自己是不是找錯 Controller、Action 或流程了
最直覺的方法就是:
點程式碼左邊的灰色區域
例如:
public IActionResult Detail(int id)
{
var model = _userService.GetDetail(id);
return View(model);
}
在:
var model = _userService.GetDetail(id);
左邊點一下。
就會出現一個紅色圓點。
代表:
這一行有 Breakpoint
再點一次,就可以取消。
也可以把游標放在那一行,按:
F9
來新增或移除中斷點。
所以可以先記:
F9
新增 / 移除 Breakpoint
因為只有放中斷點還不夠。
程式必須在:
Debug 模式

這裡執行
Visual Studio 裡通常可以按:
F5
也就是:
Start Debugging
開始偵錯
流程就是:
第一步
找到想確認的程式
↓
第二步
下 Breakpoint
↓
第三步
按 F5 啟動 Debug
↓
第四步
到瀏覽器操作功能
↓
第五步
如果程式跑到那一行
Visual Studio 就會停下來
假設網址是:
/User/Detail/10
Controller:
public IActionResult Detail(int id)
{
var model = _userService.GetDetail(id);
return View(model);
}
我想確認這個網址是不是真的進:
Detail(int id)
就可以在第一行:
var model = _userService.GetDetail(id);
下中斷點。
接著:
F5
↓
開啟網站
↓
進入 /User/Detail/10
如果 Visual Studio 跳回來,並停在這一行:
var model = _userService.GetDetail(id);
就可以先確認:
/User/Detail/10
真的有進到:
UserController.Detail()
這比單純看網址猜測可靠很多。
Visual Studio 停在某一行時,通常會看到黃色標示。
這時要注意:
黃色那一行
通常代表「接下來準備執行的程式」
例如停在:
var model = _userService.GetDetail(id);
代表這一行目前準備要執行。
不是代表:
這一行已經執行完了
這個差別很重要。
因為如果我現在想看:
model 裡面有什麼
但:
_userService.GetDetail(id)
還沒執行完。
那 model 當然可能還沒有我想看的資料。
這時候就要讓程式往下一步跑。
程式停下來之後,我最常用的是:
F10
它叫:
Step Over
逐程序
例如目前停在:
var model = _userService.GetDetail(id);
按 F10。
Visual Studio 會:
執行完這一行
↓
停在下一行
變成:
var model = _userService.GetDetail(id);
return View(model);
這時候:
GetDetail(id)
已經執行完成。
所以現在就可以查看:
model 到底拿到什麼資料
簡單記:
F10
執行這一行
但不要進去看方法內部
假設目前停在:
var model = _userService.GetDetail(id);
而我現在不是只想得到結果。
我想知道:
GetDetail()
裡面到底做了什麼?
這時就可以按:
F11
也就是:
Step Into
逐陳述式
按下去後,可能直接進到:
public UserDetailViewModel GetDetail(int id)
{
var user = _userRepository.GetById(id);
...
}
所以:
F10
我只想執行完這個方法
F11
我要進這個方法裡面看
這兩個我一開始超容易搞混。
後來就記成:
F10
跨過去
F11
鑽進去
假設我已經看完這裡,不想每一行慢慢跑。
就可以再按:
F5
這時程式會繼續正常執行。
直到:
遇到下一個 Breakpoint
才會再次停下來。
所以 Debug 時我現在最常用的是:
F5
繼續跑
F10 跨過去
跑下一行,不進方法
F11 鑽進去
跑進方法裡
F9
新增 / 移除中斷點
上一篇我們用 F12 看的是:
程式碼「寫在哪」
現在 Breakpoint 看的是:
程式「實際怎麼跑」
例如:
public IActionResult Detail(int id)
{
var model = _userService.GetDetail(id);
return View(model);
}
先在:
var model = _userService.GetDetail(id);
停住。
接著按:
F11 鑽進去看
可能進到 Service:
public UserDetailViewModel GetDetail(int id)
{
var user = _userRepository.GetById(id);
var model = new UserDetailViewModel
{
Name = user.Name,
Email = user.Email
};
return model;
}
再停在:
var user = _userRepository.GetById(id);
如果我又想知道:
Repository 查了什麼?
再按:
F11 鑽進去看
可能進到:
public User GetById(int id)
{
return _dbContext.Users
.FirstOrDefault(x => x.Id == id);
}
這樣我就真的可以看著程式跑:
Controller
↓
Service
↓
Repository
↓
Database 查詢
跟上一篇只用 F12 靜態看程式相比,感覺完全不一樣。
兩者比較後會更清楚!
回答:
這個方法寫在哪裡?
例如:
_userService.GetDetail(id)
↓
F12
↓
找到 GetDetail() 定義
但是:
你找到它
不代表這次程式真的有執行它
回答:
這次執行真的有跑到這裡嗎?
所以我現在會這樣搭配:
不知道程式在哪
↓
F12
知道程式在哪
但不知道有沒有跑到
↓
中斷點 Breakpoint
這兩個一起用,追企業專案真的差很多。
這也是實際上很常遇到的。
如果中斷點完全沒有被打到,我現在不會立刻覺得:
Visual Studio 壞掉了
我會先一個一個確認。
例如我以為按下:
儲存
會跑:
Edit()
但實際上可能跑的是:
Update()
或另一支 API。
這時中斷點當然不會停。
所以先確認:
網址
Route
HTTP Method
Controller
Action
有沒有找對。
這個也很常見。
例如 Controller:
[HttpGet]
public IActionResult Edit(int id)
{
return View();
}
下面又有:
[HttpPost]
public IActionResult Edit(EditUserViewModel model)
{
...
}
兩個方法都叫:
Edit
但是:
第一次打開頁面
↓
GET Edit
按下儲存
↓
POST Edit
如果我把中斷點下在:
GET Edit
然後一直按儲存,當然可能不會停在我要看的位置。
所以看到同名 Action 時,要特別注意:
[HttpGet]
和:
[HttpPost]
如果只是一般執行,而不是:
Start Debugging
中斷點就可能無法按照預期工作。
最基本先確認:
是不是按 F5 啟動偵錯
而不是只看網站有沒有開起來。
正常能使用的中斷點通常會顯示紅色實心圓點。
但有時可能看到:
空心的中斷點
或 Visual Studio 提示:
The breakpoint will not currently be hit
這通常代表:
目前執行的程式
和這份原始碼沒有正確對應上
可能的原因很多,例如:
程式沒有重新 Build
目前跑的不是這個專案
目前載入的是另一個版本
Debug symbols 沒有載入
這時就不是一直重新整理瀏覽器可以解決。
要先確認:
我現在 Debug 的到底是不是這份程式?
這在多專案的 Solution 裡尤其重要。
有時候最簡單的答案就是:
它真的沒走這條路
例如:
if (user == null)
{
return NotFound();
}
_userService.Update(user);
我把 Breakpoint 下在:
_userService.Update(user);
但 user 一直都是 null。
那程式會在前面:
return NotFound();
就結束。
當然永遠不會跑到 Update。
所以這時需要開始看:
程式實際走哪一條判斷?
這也是 Debug 真正有價值的地方。
一開始學中斷點,很容易只會在 Controller 下。
其實只要是會執行的 C# 程式,都可以視情況下中斷點。
例如:
Controller
Service
Repository
資料轉換方法
Helper
假設我已經確定 Controller 正常:
var model = _userService.GetDetail(id);
但 Service 結果不對。
那我就直接去 Service:
public UserDetailViewModel GetDetail(int id)
{
...
}
裡下中斷點。
這樣不用每次都從 Controller 慢慢 F11 進去。
所以我的做法會是:
第一次不知道問題在哪
↓
從入口開始追
已經大概知道是哪一層
↓
直接在那一層下中斷點
假設畫面上:
部門名稱沒有顯示
View:
@Model.DepartmentName
上一篇可以用 F12 一路找到:
public UserDetailViewModel GetDetail(int id)
{
var user = _userRepository.GetById(id);
var model = new UserDetailViewModel
{
Name = user.Name,
DepartmentName = user.DepartmentName
};
return model;
}
接著我可以在:
var user = _userRepository.GetById(id);
下 Breakpoint。
按 F5 操作畫面。
停下來後:
先確認 id 是多少
按 F10,讓 Repository 執行完。
接著確認:
user 有沒有資料?
user.DepartmentName 是不是空的?
如果:
user.DepartmentName 已經是空的
就繼續往 Repository 查。
如果:
user.DepartmentName = "資訊部"
但最後 View 還是沒有。
那問題可能在:
Entity / DTO
↓
ViewModel 轉換
↓
Controller
↓
View
後面的某一段。
這時就不用第一時間去改 SQL。
我後來覺得 Debug 最重要的觀念其實是:
不要再猜程式怎麼跑
直接讓它跑給我看
例如我原本猜:
按下儲存
↓
Update Controller
↓
Update Service
↓
Database
但中斷點一跑才發現:
按下儲存
↓
另一支 Action
↓
直接 return
那前面猜半天根本沒用!!
所以中斷點是在幫我回答:
這次到底跑了哪支程式?
有沒有進這個方法?
哪個 if 被走到了?
哪裡提早 return?
資料在哪一層開始不對?
假設接到需求:
按下按鈕後沒有反應
我現在不會立刻亂改。
我會先:
第一步
找到按鈕送去哪個 Controller / Action
↓
第二步
在 Action 第一段有效程式下中斷點
↓
第三步
F5 啟動 Debug
↓
第四步
回瀏覽器重現問題
↓
第五步
確認中斷點有沒有被打到
如果沒打到:
先查 Route / Action / HTTP Method
如果有打到:
開始 F10 / F11 往下追
這樣問題就被拆成:
根本沒進來
還是:
有進來,但執行途中出問題
這兩種情況完全不一樣。
| 快捷鍵 | 功能 | 我怎麼記 |
|---|---|---|
F9 |
新增 / 移除中斷點 | 在這裡設一個暫停點 |
F5 |
開始 / 繼續 Debug | 繼續跑 |
F10 |
Step Over | 跨過去~下一行,不進方法 |
F11 |
Step Into | 鑽進去!進方法裡面 |
再加上一篇的:
F12
找程式寫在哪裡
目前其實已經可以做到:
F12
找到程式
↓
F9
設中斷點
↓
F5
執行
↓
F10 / F11
一步一步追
這已經是我覺得看企業專案非常實用的一組基本工具。
F12 可以讓我知道:
程式碼寫在哪裡
Breakpoint 則可以讓我知道:
程式執行時到底有沒有跑到這裡
基本流程:
找到想確認的程式
↓
F9 下 Breakpoint
↓
F5 開始 Debug
↓
操作網站
↓
Visual Studio 停住
↓
F10 / F11 繼續追
其中:
F10
執行下一步,但不要進方法
F11
進到方法裡繼續看
而如果 Breakpoint 完全沒有停:
不要急著改這段程式
先確認:
是不是找錯 Action?
GET / POST 有沒有看錯?
Route 有沒有走這裡?
目前是不是 Debug 正確的專案?
程式是不是在前面就 return 了?
最重要的改變其實是:
以前:
我覺得程式「應該」會跑這裡
現在:
我直接用 Breakpoint 確認
它「到底」有沒有跑這裡
不過程式停下來之後,下一個問題馬上就來了:
好,它真的停了。
然後咧?
現在我要看哪裡?
id 是多少?
model 裡有什麼?
user 為什麼是 null?
這麼多視窗到底要看哪一個?
下一篇就繼續:
程式停下來之後要看什麼?怎麼用變數提示、Locals、Watch 和 Call Stack 找出資料到底在哪裡開始出問題?