Lesson 4 of 40 Debugging Intermediate 50 min

Advanced Debugging Techniques in Visual Studio 2026

Go beyond simple breakpoints. Learn how to diagnose bugs faster with conditional breakpoints, tracepoints, data breakpoints, Watch and Locals windows, IntelliTrace, Hot Reload, Copilot-assisted debugging, and a repeatable debugging workflow.

Lesson goal: By the end of this lesson, you should know how to choose the right debugging tool instead of repeatedly adding random breakpoints and guessing where the bug is.
Visual Studio Debugger · Break Mode
21public decimal CalculateDiscount(Order order)
22{
23 if (order.Customer == null)
24 throw new InvalidOperationException("Customer missing");
25 return order.Total > 1000 ? 0.15m : 0.05m;
26}

// Conditional breakpoint:
// order.Total > 1000 && order.Status == "Pending"

Watch

order.Total1250.00
order.StatusPending
discount0.15

Call Stack

OrderService.CalculateDiscount()
CheckoutController.Post()
Program.Main()

Copilot

Analyze why this order receives the wrong discount and suggest a safe fix.

Why Advanced Debugging Matters

Many beginners debug by guessing: they add a breakpoint, run the program, check one variable, stop, move the breakpoint, and try again. That approach works for very small programs, but it becomes slow when your application has database calls, async code, multiple services, web requests, background tasks, or UI events.

Professional debugging is more systematic. You first reproduce the bug, identify the failing condition, choose the right debugger feature, inspect the runtime state, confirm the root cause, and then make the smallest safe fix.

Find the real stateUse Locals, Watch, DataTips, Call Stack, and Immediate Window instead of guessing.
Break only when neededUse conditional, tracepoint, hit-count, dependent, and temporary breakpoints.
Diagnose historyUse IntelliTrace and diagnostic tools when the problem happened before the current line.
Fix safelyUse Hot Reload for quick edits, then run tests and review the final code carefully.

A Practical Debugging Workflow

Use this workflow whenever an application produces the wrong result, throws an exception, hangs, or behaves differently from what you expected.

1

Reproduce the problem

Write down the exact action that triggers the bug. For a web app, include the route, input values, login role, and browser action. For a desktop app, note the form, button, and data used.

2

State the expected and actual result

Example: “Expected discount is 5%, actual discount is 15% when the order status is Pending.” This helps you choose where to inspect variables.

3

Choose the right breakpoint

Use a normal breakpoint for a simple pause, a conditional breakpoint for a specific state, a tracepoint for logging without stopping, and a data breakpoint when a value changes unexpectedly.

4

Inspect runtime evidence

Check Locals, Autos, Watch, DataTips, Call Stack, Output, Exception Settings, Diagnostic Tools, and test output. Do not rely only on what the source code appears to say.

5

Apply a small fix and validate

Use Hot Reload for supported quick changes during debugging, but still rebuild, run tests, and review the final source before committing.

Choosing the Right Breakpoint Type

Breakpoints are not only red dots. Visual Studio includes several breakpoint types for different debugging situations.

Breakpoint TypeBest UseExample
Line breakpointPause at a specific lineStop before saving an order
Conditional breakpointPause only when a condition is trueorder.Total > 1000
TracepointLog a message without stopping executionPrint order ID and status to Output
Hit count breakpointBreak after a line is reached several timesStop on the 10th loop iteration
Temporary breakpointBreak once and then remove itselfInspect one execution path only
Dependent breakpointBreak only after another breakpoint is hitDebug a later method only after login succeeds
Data breakpointBreak when a property or memory value changesFind who changes Customer.Status
Productivity tip: Right-click a breakpoint and open Settings. From there you can add conditions, actions, hit counts, labels, and temporary behavior.

Conditional Breakpoints and Tracepoints

A conditional breakpoint stops only when a condition is true. This is useful when the same line runs hundreds of times but fails only for one record or one user action.

// Break only when a high-value pending order is processed order.Total > 1000 && order.Status == "Pending" // Break only when a specific customer is loaded customer.Email == "demo@example.com"

A tracepoint is different. It writes a message to the Output window and continues running. Use tracepoints when stopping the application would change timing or interrupt a user workflow.

// Tracepoint message example "Order {order.Id}, Status={order.Status}, Total={order.Total}"

Watch, Locals, DataTips, and Call Stack

When Visual Studio pauses at a breakpoint, the most important question is: what is the real runtime state? The code may look correct, but the actual values may tell a different story.

Locals

Shows variables in the current scope. Use it first when you are inside a method and want a quick view of current values.

Watch

Lets you pin expressions that matter, such as order.Customer?.Email or items.Count.

DataTips

Hover over variables while stopped at a breakpoint to inspect values inline without opening another window.

Call Stack

Shows how the program reached the current line. This is essential when the bug starts in a caller, not in the current method.

Exception Debugging and First-Chance Exceptions

When an exception occurs, do not only read the last error message. Inspect the exception type, message, call stack, inner exception, local variables, and the line where the exception first occurred.

// Common example: NullReferenceException public decimal GetDiscount(Order order) { // Break here if Customer is null before using it return order.Customer.IsVip ? 0.20m : 0.05m; }

Use Exception Settings when you want Visual Studio to break at the moment an exception is thrown, not later after the exception has been handled somewhere else.

Beginner warning: A handled exception may not crash the app, but it can still explain a wrong result, empty page, failed database save, or missing UI update.

Data Breakpoints: Break When a Value Changes

A data breakpoint is useful when you know a value becomes wrong but you do not know which line changes it. Instead of searching manually, ask the debugger to pause when that value changes.

  1. Start debugging and pause at a normal breakpoint.
  2. Open Locals, Autos, or Watch.
  3. Right-click a supported property or value.
  4. Select Break when value changes.
  5. Continue debugging and wait for Visual Studio to pause at the mutation point.

This is especially useful for state bugs, unexpected property changes, UI model updates, and values modified by background logic.

Historical Debugging with IntelliTrace

IntelliTrace records selected events and lets you move backward and forward through the execution history. This helps when the important event happened before the current breakpoint.

Use IntelliTrace when you need to answer questions such as:

  • Which database call happened before this exception?
  • Which user action caused the current state?
  • What method ran before the wrong value appeared?
  • Which event was triggered before the UI froze?
Edition note: IntelliTrace and historical debugging are typically Visual Studio Enterprise features. If you use Community or Professional, focus on breakpoints, logs, diagnostic tools, and tests.

Hot Reload and Edit-and-Continue

Hot Reload lets you apply many code changes while debugging, without stopping and restarting the whole session. This is useful for small logic changes, UI tweaks, and quick validation while the application is already running.

// Before return order.Total > 1000 ? 0.15m : 0.05m; // After: add a safer business rule during debugging return order.Status == "Paid" && order.Total > 1000 ? 0.15m : 0.05m;

Hot Reload is powerful, but not every edit is supported. If Visual Studio reports that a change cannot be applied, stop debugging, rebuild, and run the application again.

Diagnostic Tools, Output Window, and Logs

The debugger shows source-level evidence, but real applications often need runtime diagnostics too. Use the Diagnostic Tools window to watch CPU, memory, events, and exceptions while debugging. Use the Output window to review build messages, tracepoint output, debug messages, and runtime logs.

using Microsoft.Extensions.Logging; public class OrderService(ILogger<OrderService> logger) { public void Save(Order order) { logger.LogInformation("Saving order {OrderId} with total {Total}", order.Id, order.Total); // Save order here } }

Debugging with GitHub Copilot

Copilot can help explain exceptions, summarize call stacks, suggest conditional breakpoints, analyze variable values, and propose fixes. It is most useful when you provide runtime evidence, not just a vague complaint.

Good Copilot debugging prompt

“This ASP.NET Core action throws a NullReferenceException. I am stopped at the exception. Here are the local values: order.Customer is null, order.Id is 1042, and the call stack starts from CheckoutController.Post. Explain the likely cause and suggest the smallest safe fix.”

Use Copilot as a debugging assistant, not as an automatic authority. Always inspect the suggested fix, run the test case that reproduces the bug, and check whether the change creates a new bug elsewhere.

Hands-On Exercise: Debug a Wrong Discount

Create a small console app and intentionally add a logic bug. Then use Visual Studio debugging tools to find and fix it.

public class Order { public decimal Total { get; set; } public string Status { get; set; } = "Pending"; } static decimal GetDiscount(Order order) { // Bug: pending orders should not receive the high discount yet return order.Total > 1000 ? 0.15m : 0.05m; } var order = new Order { Total = 1250, Status = "Pending" }; Console.WriteLine(GetDiscount(order));
  1. Set a breakpoint inside GetDiscount.
  2. Add a conditional breakpoint: order.Total > 1000.
  3. Add order.Status to the Watch window.
  4. Use Step Over to inspect the return line.
  5. Fix the condition so high discount applies only to paid orders.
  6. Run again and confirm the result.

Best Practices and Common Mistakes

Do

  • Reproduce the bug before changing code.
  • Use conditions to avoid stopping too often.
  • Inspect the call stack when a method is called unexpectedly.
  • Use tracepoints when you need logging without stopping.
  • Run tests after every fix.

Avoid

  • Changing code before understanding the root cause.
  • Accepting AI-generated fixes without review.
  • Ignoring handled exceptions.
  • Leaving temporary debug code in production.
  • Debugging stale code without rebuilding.
Visual Studio 2026 Made Easy book cover
Recommended Companion Book

Visual Studio 2026 Made Easy

Build real applications with C#, VB.NET, Python, JavaScript, C++, .NET 10, debugging tools, and AI-assisted development workflows. A practical companion for readers who want a structured path beyond a single web lesson.