diff --git a/.gitignore b/.gitignore index 08a2456..637cbde 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ tst/ obj/ bin/ +.vscode/ *.sln diff --git a/032_Debug_console_apps/ejm_debug/Program.cs b/032_Debug_console_apps/ejm_debug/Program.cs index 1850202..97814e0 100644 --- a/032_Debug_console_apps/ejm_debug/Program.cs +++ b/032_Debug_console_apps/ejm_debug/Program.cs @@ -1,4 +1,6 @@ -string[] students = new string[] {"Sophia", "Nicolas", "Zahirah", "Jeong"}; +string[] students = new string[] { + "Sophia", "Nicolas", "Zahirah", "Jeong" +}; int studentCount = students.Length; diff --git a/033_Debug_console_apps_2/033_csharp.md b/033_Debug_console_apps_2/033_csharp.md new file mode 100644 index 0000000..9b5e476 --- /dev/null +++ b/033_Debug_console_apps_2/033_csharp.md @@ -0,0 +1,1069 @@ +## Implement the Visual Studio Code debugging tools for C# + +### Introduction + +The faster you discover and identify bugs, the faster you can get your code +stabilized and released. Visual Studio Code supports code debugging for C# and +most other software development languages through the use of Extensions. Once +you've learned to use Visual Studio Code's debug tools, you'll spend less time +wondering why your code stopped working and more time developing great +applications. + +Suppose you're using Visual Studio Code to develop a C# console application. +The primary purpose of the application is to process customer data based on +business rules. You develop the application using a small sample data set and +it runs without errors. However, when you run the code using the larger data +set, your code produces some unexpected results. You've read through the code +several times but it's difficult to find the errors in your logic. You've heard +that Visual Studio Code has good debugger tools, but you've never had to use +them. You can't waste any more time reading through the code. You decide that +learning the debugger tools is your best chance for completing the project on +time. + +In this module, you learn how to effectively debug C# programs in Visual Studio +Code using breakpoints and other debugging tools, such as resources in the RUN +AND DEBUG view. + +By the end of this module, you'll be able to configure and use the Visual Studio +Code debugger tools for C#. + +#### Learning objectives + +In this module, you will: + +- Configure the Visual Studio Code debugger for a C# program. +- Create breakpoints and step through your code to isolate issues. +- Inspect your program state at any execution step. +- Use the call stack to find the source of an exception. + +Ultimately, you'll be able to isolate code bugs efficiently using the debugger +tools, and you won't need to rely on `Console.WriteLine` anymore. + +--- + +## Examine the Visual Studio Code debugger interface + +The Visual Studio Code user interface provides several ways to configure debug +options and launch debug sessions. + +### Debug features in the Visual Studio Code user interface + +Visual Studio Code includes several user interface features that will help you +to configure, start, and manage debug sessions: + +- Configure and launch the debugger: The Run menu and RUN AND DEBUG view can +both be used to configure and launch debug sessions. +- Examine application state: The RUN AND DEBUG view includes a robust interface +that exposes various aspects of your application state during a debug session. +- Runtime execution control: The Debug toolbar provides high-level runtime +controls during code execution. + +> Note +> This Unit introduces you to a lot of debugging tools and terminology. Please +keep in mind that this is your first look at these tools, not your last. You'll +have an opportunity to complete hands-on activities with most of these tools +during this module. Try not to feel overwhelmed by the volume of information +that's presented. + +--- + +### Run menu options + +The Visual Studio Code Run menu provides easy access to some common run and +debug commands. + +
+ +![img](./img/code_oss_debuger.png) + +
+ +The Run menu provides menu options that are grouped into six sections. + +1. Start and stop applications. This section of the menu includes options for +starting and stopping code execution, with and without the debugger attached. + +2. Launch configurations. This section of the menu provides access to examine +or create launch configurations. + +3. Runtime control. This section of the menu enables the developer to control +how they want to advance through the code. Controls are enabled when execution +has paused during a debug session. + +4. Set Breakpoints. This section of the menu enables the developer to set +breakpoints on code lines. Code execution pauses on Breakpoints during a debug +session. + +5. Manage Breakpoints. This section of the menu enables the developer to manage +breakpoints in bulk rather than individually. + +6. Install Debuggers. This section of the menu opens the Visual Studio Code +EXTENSIONS view filtered for code debuggers. + +### Run and Debug view user interface + +The RUN AND DEBUG view provides access to runtime tools that can be invaluable +during the debug process. + +1. Run and Debug controls panel. Used to configure and start a debug session. + +2. VARIABLES section. Used to view and manage variable state during a debug +session. + +3. WATCH section. Used to monitor variables or expressions. For example, you +could configure an expression using one or more variables and watch it to see +when a particular condition is met. + +4. CALL STACK section. Used to keep track of the current point of execution +within the running application, starting with the initial point of entry into +the application. The call stack shows which method is currently being executed, +as well as the method or methods in the execution path that led to the current +point of execution (current line of code). + +5. BREAKPOINTS section. Displays the current breakpoint settings. + +6. Debug toolbar. Used to control code execution during the debug process. This +toolbar is only displayed while the application is running. + +7. Current execution step. Used to identify the current execution step by +highlighting it in the Editor. In this case, the current execution step is a +breakpoint (breakpoints are marked with a red dot to the left of the line +number). + +8. DEBUG CONSOLE. Used to display messages from the debugger. The DEBUG CONSOLE +panel is the default console for console applications and is able to display +output from `Console.WriteLine()` and related `Console` output methods. + +### Controls panel for the Run and Debug view + +At the top of the RUN AND DEBUG view, you can find the launch controls: + +
+ +![img](./img/code_oss_debug_panel.png) + +
+ +1. Start debugging. This button (a green arrow) is used to start a debug +session. + +2. Launch configurations. This dropdown menu provides access to launch +configurations. The selected option is displayed. + +3. Open 'launch.json'. This button (a gear shape) can be used to open the +`launch.json` file, where you can edit the launch configuration if needed. + +4. Views and More Actions. This button (an ellipsis) enables you to show/hide +sections of the debug panel as well as the DEBUG CONSOLE panel. + +### Debug toolbar + +The Debug toolbar provides execution controls while your application is running. + +
+ +![img](./img/code_oss_debug_toolbar.png) + +
+ +1. Pause/Continue. This button can be used to pause execution when the code is +running and Continue when code execution has been paused. + +2. Step Over. This button can be used to execute the next method as a single +command without inspecting or following its component steps. + +3. Step Into. This button can be used to enter the next method or code line and +observe line-by-line execution steps. + +4. Step Out. When inside a method, this button can be used to return to the +earlier execution context by completing all remaining lines of the current +method as though they were a single command. + +5. Restart. This button can be used to terminate the current program execution +and start debugging again using the current configuration. + +6. Stop. This button can be used to terminate the current program execution. + +In addition to six execution controls, the Debug toolbar provides a "handle" on +the left side that enables the developer to reposition the toolbar, and a "More" +dropdown on the right side that enables the developer to disconnect the +debugger. + +> Note +> You can use the setting `debug.toolBarLocation` to control the location of +the debug toolbar. It can be floating (the default), docked to the RUN AND +DEBUG view, or hidden. A floating debug toolbar can be dragged horizontally and +down to the Editor area. + +### Recap + +Here are a few important things to remember from this unit: + +The Visual Studio Code user interface can be used to configure, start, and +manage debug sessions. The launch.json file contains the launch configurations +for your application. + +- The Run menu provides easy access to common run and debug commands grouped +into six sections. +- The RUN AND DEBUG view provides access to runtime tools, including the Run +and Debug controls panel. The sections of the RUN AND DEBUG view are VARIABLES, +WATCH, CALL STACK, and BREAKPOINTS. +- The Debug toolbar provides execution controls while your application is +running such as pause/continue, step over, step into, step out, restart and +stop. +- The DEBUG CONSOLE is used to display messages from the debugger. The DEBUG +CONSOLE can also display console output from your application. + +--- + +## Exercise - Run code in the debug environment + +The Visual Studio Code user interface enables developers to run their code in a +debug environment. Support for debugging is provided by extensions, and for C# +developers, debugger support is provided by the same extension that provides +support for code development and IntelliSense. + +### Debugger and application interaction + +A code debugger can be used to pause and resume code execution, examine +variable state, and even change the values assigned to variables at runtime. +You may be wondering, how can the debugger control and modify a running +application? The short answer is, the debugger has access to the application's +runtime environment and executable code. + +> Note +> Debugger interaction with the runtime environment is an advanced topic. In +addition, understanding how the debugger works behind the scenes isn't a +requirement for using the debugger. However, the following description may +satisfy your curiosity. + +The Visual Studio Code debugger for C# uses the .NET Core runtime to launch and +interact with an application. When you start the debugger, it creates a new +instance of the runtime and runs the application within that instance. The +runtime includes an application programming interface (API), which the debugger +uses to attach to the running process (your application). + +Once your application is running and the debugger is attached, the debugger +communicates with the running process using the .NET Core runtime's debugging +APIs and a standard debug protocol. The debugger can interact with the process +(the application running within the .NET runtime instance) by setting +breakpoints, stepping through code, and inspecting variables. Visual Studio +Code's debugger interface enables you to navigate the source code, view call +stacks, and evaluate expressions. + +The most common way to specify a debug session is a launch configuration in the +launch.json file. This approach is the default option enabled by the debugger +tools. For example, if you create a C# console application and select Start +Debugging from the Run menu, the debugger uses this approach to launch, attach +to, and then interact with your application. + +### Create a new code project + +The first step in learning the debugger tools is creating a code project that +you can run in the debugger. + +- Open a new instance of Visual Studio Code. + +- On the File menu, select **Open Folder**. + +- On the Open Folder dialog, navigate to your folder. + +- On the Open Folder dialog, select New folder. + +- Name the new folder **Debug101**, and then select **Select Folder**. + +- On the **Terminal** menu, select **New Terminal**. + + A .NET CLI command can be used to create a new console app. + +- At the TERMINAL panel command prompt, enter the following command: + + ```pwsh + dotnet new console + ``` + +- Close the TERMINAL panel. + +### Examine launch configurations for debugging + +Visual Studio Code uses a launch configuration file to specify the application +that runs in the debug environment. + +If the Debug101 folder doesn't include a Debug101.sln file, select `Program.cs`, +and then verify that a .sln file is created. + +Opening a C# code file prompts the environment to check for project files. The +.sln file is a solution file that is used by Visual Studio to manage projects +and is usually created automatically when you create a new project in Visual +Studio Code. The .sln file is used by the debugger to identify the project that +should be run in the debug environment. + +On the View menu, select **Command Palette**. + +At the command prompt, enter .net: g and then select **`.NET: Generate Assets for +Build and Debug`**. + +Notice the new `.vscode` folder that has been added to your project folder. + +The `.vscode` folder contains files that are used to configure the debug +environment. + +Expand the `.vscode` folder, and then select the launch.json file. + +Take a minute to examine the launch.json file. + +The launch configurations file can include multiple configurations. Each +configuration includes a collection of attributes that are used to define that +configuration. + +Notice that the `prelaunchTask` attribute specifies a build task. + +In the `.vscode` folder, select **`tasks.json`**. + +Notice that the tasks.json file contains the *build* task for your code +project. + +Close the `launch.json` and `tasks.json` files. + +You take a closer look at the launch configuration attributes later in this +module. + +### Run your code from the Run menu + +The Run menu in Visual Studio Code provides the option to run your code with or +without the debugger. + +Open the Program.cs file. + +Replace the contents of your Program.cs file with the following code: + +```cs +// This code uses a names array and corresponding methods to display +// greeting messages +string[] names = new string[] { "Sophia", "Andrew", "AllGreetings" }; +string messageText = ""; + +foreach (string name in names) { + if (name == "Sophia") + messageText = SophiaMessage(); + else if (name == "Andrew") + messageText = AndrewMessage(); + else if (name == "AllGreetings") + messageText = SophiaMessage(); + messageText = messageText + "\n\r" + AndrewMessage(); + Console.WriteLine(messageText + "\n\r"); +} + +bool pauseCode = true; +while (pauseCode == true); + +static string SophiaMessage() { + return "Hello, my name is Sophia."; +} + +static string AndrewMessage() { + return "Hi, my name is Andrew. Good to meet you."; +} +``` + +On the **File** menu, select **Save**. + +Open the **Run** menu. + +Notice that the **Run** menu provides options for running your code with or +without debugging. + +On the **Run** menu, select **Run Without Debugging** + +Notice that the DEBUG CONSOLE panel displays console output, and that the +**Debug toolbar** displays execution controls. + +The DEBUG CONSOLE panel should be displayed below the code Editor. By default, +the **Debug toolbar** (the small toolbar displaying code execution controls) is +located above the code Editor and horizontally centered on the Visual Studio +Code window. + +On the **Debug toolbar**, select **Stop**. + +### Start a debug session from the Run menu + +The Run menu includes the option to start a debug session. + +On the **Run** menu, select **Start Debugging** + +Take a minute to review the messages displayed in the DEBUG CONSOLE panel. + +The output from your application is the same as when you ran without debugging, +but other messages related to preparing the debug environment are displayed. + +Notice the messages about loading .NET resources and your Debug101 application. + +The first two messages report loading the .NET Core library and then your +Debug101 application. + +```txt +Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.4\System.Private.CoreLib.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled. +Loaded 'C:\Users\someuser\Desktop\Debug101\bin\Debug\net7.0\Debug101.dll'. Symbols loaded. +``` + +The debugger uses a special instance of the .NET runtime to control the +execution of your application and evaluate application state. + +On the Debug toolbar, select Stop. + +### Run your code from the Run and Debug view + +The RUN AND DEBUG view in Visual Studio Code supports a rich debugging +experience. + +Switch to the RUN AND DEBUG view. + +
+ +![img](./img/code_oss_debug_01.png) + +
+ +In the RUN AND DEBUG view, select Start Debugging. + +The **Start Debugging** button is the green arrow on the control panel at the +top of the view. + +Notice that the DEBUG CONSOLE panel shows the same messages about configuring +the debugger that were displayed when starting a debug process from the **Run** +menu. + +On the **Debug toolbar**, select **Stop**. + +### Examine the output from your application + +Before closing the DEBUG CONSOLE panel, take a minute to review the output that +your code produced. + +Notice that Andrew's greeting message is repeated unexpectedly. + +During the remainder of this module, you'll use the Visual Studio Code debugger +tools to investigate coding issues. + +### Recap + +Here are a few important things to remember from this unit: + +- The Visual Studio Code debugger for C# uses the .NET Core runtime to launch and interact with an application. +- The Visual Studio Code Run menu has options to start an application with and without the debugger attached. +- The Debug toolbar includes a button to Stop a running process. +- The RUN AND DEBUG view includes an option to start debugging an application. + +--- + +## Examine breakpoint configuration options + +Debuggers are used to help you to analyze your code and can be used to control +your program's runtime execution. When you start the Visual Studio Code +debugger, it immediately begins executing your code. Because your code executes +in micro-seconds, effective code debugging depends on your ability to pause the +program on any statement within your code. Breakpoints are used to specify +where code execution pauses. + +### Set breakpoints + +Visual Studio Code provides several ways to configure breakpoints in your code. +For example: + +- Code Editor: You can set a breakpoint in the Visual Studio Code Editor by +clicking in the column to the left of a line number. +- Run menu: You can toggle a breakpoint on/off from the Run menu. The current +code line in the Editor specifies where the Toggle Breakpoint action is applied. + +When a breakpoint is set, a red circle is displayed to the left of the line +number in the Editor. When you run your code in the debugger, execution pauses +at the breakpoint. + +
+ +![img](./img/code_oss_debug_02.png) + +
+ +### Remove, disable, and enable breakpoints + +After setting breakpoints in your application and using them to isolate an +issue, you may want to remove or disable the breakpoints. + +To remove a breakpoint, repeat the action used to set a breakpoint. For example, +click the red circle to the left of the line number or use the toggle +breakpoint option on the Run menu. + +What if you want to keep a breakpoint location, but you don't want it to +trigger during your next debug session? Visual Studio Code enables you to +"disable" a breakpoint rather than removing it altogether. To disable an active +breakpoint, right-click the red dot to the left of the line number, and then +select Disable Breakpoint from the context menu. + +
+ +![img](./img/code_oss_debug_03.png) + +
+ +When you disable a breakpoint, the red dot to the left of the line number is +changed to a grey dot. + +> Note +> The context menu that appears when you right-click a breakpoint also includes +the options to **Remove Breakpoint (Delete)** and **Edit Breakpoint**. The +**Edit Breakpoint** option is examined in the **Conditional breakpoints +Logpoints** section later in this unit. + +In addition to managing individual breakpoints in the Editor, the **Run** menu +provides options for performing bulk operations that act on all breakpoints: + +- **Enable All Breakpoints**: Use this option to enable all disabled breakpoints. +- **Disable All Breakpoints**: Use this option to disable all breakpoints. +- **Remove All Breakpoints**: Use this option to remove all breakpoints (both +enabled and disabled breakpoints are removed). + +### Conditional breakpoints + +A conditional breakpoint is a special type of breakpoint that only triggers +when a specified condition is met. For example, you can create a conditional +breakpoint that pauses execution when a variable named `numItems` is greater +than 5. + +You've already seen that right-clicking a breakpoint opens a context menu that +includes the **Edit Breakpoint** option. Selecting **Edit Breakpoint** enables +you to change a standard breakpoint into a conditional breakpoint. + +
+ +![img](./img/code_oss_debug_04.png) + +
+ +In addition to editing an existing breakpoint, you can also set a conditional +breakpoint directly. If you right-click (rather than left-click) to set a new +breakpoint, you can choose to create a conditional breakpoint. + +When you create a conditional breakpoint, you need to specify an expression +that represents the condition. + +Each time the debugger encounters the conditional breakpoint, it evaluates the +expression. If the expression evaluates as `true`, the breakpoint is triggered +and execution pauses. If the expression evaluates as `false`, execution +continues as if there was no breakpoint. + +For example, suppose you need to debug some code that's inside the code block +of a `for` loop. You've noticed that the issue you're debugging only occurs +after the loop has completed several iterations. You decide that you want the +breakpoint to trigger once the loop's iteration control variable, `i`, is +greater than three. You create a conditional breakpoint and specify the +expression `i > 3`. + +
+ +![img](./img/code_oss_debug_05.png) + +
+ + +When you run your code in the debugger, it skips over your breakpoint until the +iteration when `i > 3` evaluates as true. When `i = 4`, execution pauses on +your conditional breakpoint. + +### Support for `Hit Count` breakpoints and `Logpoints` + +The C# debugger for Visual Studio Code also supports `Hit Count` breakpoints +and `Logpoints`. + +A 'hit count' breakpoint can be used to specify the number of times that a +breakpoint must be encountered before it will 'break' execution. You can +specify a hit count value when creating a new breakpoint (with the Add +Conditional Breakpoint action) or when modifying an existing one (with the Edit +Condition action). In both cases, an inline text box with a dropdown menu opens +where you can enter the hit count value. + +A 'Logpoint' is a variant of a breakpoint that does not "break" into the +debugger but instead logs a message to the console. Logpoints are especially +useful for injecting logging while debugging production environments that +cannot be paused or stopped. A Logpoint is represented by a "diamond" shaped +icon rather than a filled circle. Log messages are plain text but can include +expressions to be evaluated within curly braces `{}` + +Logpoints can include a conditional 'expression' and/or 'hit count' to further +control when logging messages are generated. For example, you can combine a +Logpoint message of `i = {i}` with Hit Count condition `>4` to generate log +messages as follows: + +### Recap + +Here are a few important things to remember from this unit: + +- Visual Studio Code enables setting breakpoints in the code editor or from the +**Run menu**. Breakpoint code lines are marked with a red dot to the left of the +line number. +- Breakpoints can be removed or disabled using the same options used to set +them. Bulk operations that affect all breakpoints are available on the **Run** +menu. +- Conditional breakpoints can be used to pause execution when a specified +condition is met or when a 'hit count' is reached. +- Logpoints can be used to log information to the terminal without pausing +execution or inserting code. + +--- + +## Exercise + +### Set breakpoints + +Breakpoints are used during the debug process pause execution. This enables you +to track variables and examine the sequence in which your code is executed. +Breakpoints are a great way to start your debug process. + +### Set a breakpoint + +Earlier in this module you completed an exercise where you ran an application +in the debugger. The application displayed "greeting messages" in the DEBUG +CONSOLE panel. At the end of the exercise, you noticed that the code repeats +Andrew's greeting in an unexpected way. + +In this exercise, you'll use a breakpoint to help you identify the issue. + +Ensure that your Program.cs file contains the following code sample: + +```cs +//This code uses a names array and corresponding methods to display +//greeting messages +string[] names = new string[] { "Sophia", "Andrew", "AllGreetings" }; + +string msg_txt = ""; + +foreach (string name in names) { + if (name == "Sophia") { + msg_txt = sophia_msg(); + } else if (name == "Andrew") { + msg_txt = andrew_msg(); + } else if { (name == "AllGreetings") + msg_txt = sophia_msg(); + msg_txt = msg_txt + "\n\r" + andrew_msg(); + } + Console.WriteLine(msg_txt + "\n\r"); +} + +bool pause_code = true; +while (pause_code == true); + +static string sophia_msg() { + return "Hello, my name is Sophia."; +} + +static string andrew_msg() { + return "Hi, my name is Andrew. Good to meet you."; +} +``` + +Use the Visual Studio Code debugger tools to set a breakpoint on the first code +line inside the foreach loop. + +> Tip +> One easy option for toggling on/off a breakpoint is to select (left-click) +the area to the left of the line number. Breakpoints can also be set by using +the Run menu and by using keyboard shortcuts. + +On the **Run** menu, select **Start Debugging**. + +Notice that code execution pauses at the breakpoint, and that the current code +line is highlighted in the Editor. + +On the Debug controls toolbar, select Step Into. + +You can hover the mouse pointer over the buttons on the **Debug controls** +toolbar to display the button labels. + +Notice that code execution advances to the following code line and pauses: + +```cs +messageText = SophiaMessage(); +``` + +This code line assigns the return value of the `sophia_msg` method to the +string variable `messageText`. + +Take a moment to consider why selecting **Step Into** produced this result. + +- The **Step Into** button is used to advance to the next executable statement. +- Since the first element in the `names` array is `Sophia` and the `if` +statement is checking for the name `Sophia`, the expression evaluates to `true` +and code execution moves into the code block of the `if` statement. + +On the **Debug controls** toolbar, select **Step Into**. + +Notice that code execution advances to the `sophia_msg` method and pauses. + +The **Step Into** button has advanced to the next executable code line. The +next executable code line isn't the next line number in the file, it's the next +statement in the execution path. In this case, the next executable statement is +the entry point to the `sophia_msg` method. + +On the **Debug controls** toolbar, select Step **Out**. + +Notice that code execution returns to the code line that called the +`sophia_msg` method and pauses. + +Take a moment to consider why selecting **Step Out** produced this result. + +When inside a method, the **Step Out** button completes the remaining lines of +the current method and then returns to the execution context that invoked the +method. + +On the **Debug controls** toolbar, select **Step Into**. + +Notice that code execution advances to the following code line and pauses: + +```cs +messageText = messageText + "\n\r" + AndrewMessage(); +``` + +Take a moment to consider why execution advanced to this code line. + +Although the code indentation implies that this code line is part of the code +block for the `else if` statement, it isn't. Using curly braces `{}` to define +the code blocks for this `if - else if` structure would have helped to avoid +this bug. As the code is written, Andrew's message will be added to `msg_txt` +each time the loop iterates. + +### Verify your code updates + +Once you've isolated an issue in your code, you should update your code and +then verify that the issue has been fixed. + +On the **Debug controls** toolbar, select **Stop**. + +Take a minute to fix your code logic. + +You have a few options for fixing the identified issue in your code. For +example: + +- You could keep the existing code lines and add curly braces `{}` to the `if` +structure for each code block. + +- You could merge the two code lines that follow the final `else if` statement, +forming a single statement as follows: + +```cs +} else if (name == "AllGreetings") { + msg_txt = sophia_msg() + "\n\r" + andrew_msg(); +} +``` + +Either way, your updated code must include the call to `andrew_msg` within the +code block when `name == "AllGreetings"`. + +On the **File** menu, select **Save**. + +Use the debugger UI tools to clear the breakpoint that you set earlier. + +On the **Run** menu, select **Start Debugging**. + +Verify that your code now produces the expected results. + +```txt +Hello, my name is Sophia. + +Hi, my name is Andrew. Good to meet you. + +Hello, my name is Sophia. +Hi, my name is Andrew. Good to meet you. +``` + +On the **Debug controls** toolbar, select **Stop**. + +Congratulations! You've successfully used the Visual Studio Code debugger to +help you isolate and correct a logic issue. + +### Recap + +Here are a few important things to remember from this unit: + +- Use breakpoints to pause code execution during a debug session. +- Use **Step Into** from the **Debug controls** toolbar to observe the next +executable code line. +- Use **Step Out** from the **Debug controls** toolbar to advance through the +current method and back to the code line that called the method. + +--- + +## Examine the launch configurations file + +You've already seen that Visual Studio Code uses the launch.json file to +configure the debugger. If you're creating a simple C# console application, it's +likely that Visual Studio Code generates a launch.json file that has all of the +information you need to successfully debug your code. However, there are cases +when you need to modify a launch configuration, so it's important to understand +the attributes of a launch configuration. + +### Attributes of a launch configuration + +The `launch.json` file includes one or more launch `configurations` in the +configurations list. The launch configurations use attributes to support +different debugging scenarios. The following attributes are mandatory for every +launch configuration: + +- `name`: The reader-friendly name assigned to the launch configuration. +- `type`: The type of debugger to use for the launch configuration. +- `request`: The request type of the launch configuration. + +```json +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net8.0/ejm_debug.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} +``` + +This section defines some of the attributes you may encounter. + +### Name + +The `name` attribute specifies the display name for the launch configuration. +The value assigned to `name` appears in the launch configurations dropdown (on +the controls panel at the top of the RUN AND DEBUG view). + +### Type + +The `type` attribute specifies the type of debugger to use for the launch +configuration. A value of `codeclr` specifies the debugger type for .NET 5+ and +.NET Core applications (including C# applications). + +### Request + +The `request` attribute specifies the request type for the launch configuration. +Currently, the values `launch` and `attach` are supported. + +### PreLaunchTask + +The `preLaunchTask` attribute specifies a task to run before debugging your +program. The task itself can be found in the `tasks.json` file, which is in the +`.vscode` folder along with the `launch.json` file. Specifying a prelaunch task +of `build` runs a `dotnet build` command before launching the application. + +### Program + +The `program` attribute is set to the path of the application dll or .NET Core +host executable to launch. + +This property normally takes the form: +`${workspaceFolder}/bin/Debug//`. + +Where: + +- `` is the framework that the debug project is being built +for. This value is normally found in the project file as the 'TargetFramework' +property. +- `` is the name of debugged project's build output dll. This +property is normally the same as the project file name but with a '.dll' +extension. + +For example: `${workspaceFolder}/bin/Debug/net7.0/Debug101.dll` + +> Note +> The **.dll** extension indicates that this file is a dynamic link library +(dll) file. If your project is named Debug101, a file named **Debug101.dll** is +created when a build task compiles your program using the Program.cs and +Debug101.csproj files. You can find the **Debug101.dll** file in the EXPLORER +view by expanding the "bin" and "Debug" folders, and then opening a folder that +represents the .NET framework used by your code project, such as "net7.0". The +.NET Framework version is specified in your .csproj file. + +### Cwd + +The `cwd` attribute specifies the working directory of the target process. + +### Args + +The `args` attribute specifies the arguments that are passed to your program at +launch. There are no arguments by default. + +### Console + +The `console` attribute specifies the type of console that's used when the +application is launched. The options are `internalConsole`, +`integratedTerminal`, and `externalTerminal`. The default setting is +`internalConsole`. The console types are defined as: + +- The `internalConsole` setting corresponds to the DEBUG CONSOLE panel in the +Panels area below the Visual Studio Code Editor. +- The `integratedTerminal` setting corresponds to the OUTPUT panel in the +Panels area below the Visual Studio Code Editor. +- The `externalTerminal` setting corresponds to an external terminal window. +The Command Prompt application that comes with Windows is an example of a +terminal window. + +> Important +> The DEBUG CONSOLE panel doesn't support console input. For example, the DEBUG +CONSOLE can't be used if the application includes a `Console.ReadLine()` +statement. When you're working on a C# console application that reads user +input, the `console` setting must be set to either `integratedTerminal` or +`externalTerminal`. Console applications that write to the console, but don't +read input from the console, can use any of the three console settings. + +### Stop at Entry + +If you need to stop at the entry point of the target, you can optionally set +`stopAtEntry` to be `true`. + +### Edit a launch configuration + +There are lots of scenarios when you might need to customize the launch +configuration file. Many of those scenarios involve advanced or complex project +scenarios. This module focuses on two simple scenarios when updating the launch +configuration file is required: + +- Your C# console application reads input from the console. +- Your project workspace includes more than one application. + +### Update the launch configuration to accommodate console input + +As you read earlier, the DEBUG CONSOLE panel doesn't support console input. If +you're debugging a console application that relies on user input, you need to +update the `console` attribute in the associated launch configuration. + +To edit the `console` attribute: + +Open the `launch.json` file in the Visual Studio Code Editor. + +Locate the **console** attribute. + +Select the colon and assigned value, and then enter a colon character. + +Notice that when you overwrite the existing information with a colon, Visual +Studio Code IntelliSense displays the three options in a dropdown list. + +
+ +![img](./img/code_oss_debug_06.png) + +
+ +Select either `integratedTerminal` or `externalTerminal`. + +Save the `launch.json` file. + +### Update the launch configuration to accommodate multiple applications + +If your workspace has only one launchable project, the C# extension will +automatically generate the `launch.json` file. If you have more than one +launchable project, then you need to modify your `launch.json` file manually. +Visual Studio Code generates a `launch.json` file using the basic template that +you can update. In this scenario, you create separate configurations for each +application that you want to debug. Prelaunch tasks, such as a build task, can +be created in the `tasks.json` file. + +Suppose that you're working on a coding project that includes several console +applications. The root project folder, **SpecialProjects**, is the workspace +folder that you open in Visual Studio Code when you work on your code. You have +two applications that you're developing, **Project123** and **Project456**. +You use the RUN AND DEBUG view to debug the applications. You want to select +the application that you're debugging from the user interface. You also want +any saved code updates to be compiled prior to attaching the debugger to your +application. + +You can achieve the requirements for this scenario by updating the `launch.json` +and `tasks.json` files. + +The following screenshot shows the EXPLORER view and the folder structure +containing ***Project123*** and ***Project456***. + +
+ +![img](./img/code_oss_debug_07.png) + +
+ +Notice that the `name`, `preLaunchTask`, and `program` fields are all +configured for a specific application. + +The `name` attribute specifies the selectable launch option that's displayed in +the RUN AND DEBUG view user interface, the `program` attribute specifies the +path to your application. The `preLaunchTask` attribute is used to specify the +name of the task that's performed prior to launching the debugger. The +`tasks.json` file contains the named tasks and the information required to +complete the task. + +The following example shows how you could configure the tasks.json file. In +this case, the named tasks specify build operations that are specific to the +"Project123" and "Project456" applications. The build task ensures that any +saved edits are compiled and represented in the corresponding .dll file that's +attached to the debugger. + +```json +"version": "2.0.0", +"tasks": [ + { + "label": "buildProject123", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Project123/Project123.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "buildProject456", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/Project456/Project456.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } +] +``` + +With your updates to the launch.json and tasks.json files in place, the RUN AND +DEBUG view displays launch options for debugging either the Project123 or +Project456 application. The following screenshot shows the names of the launch +configurations displayed in the launch configuration dropdown: + +
+ +![img](./img/code_oss_debug_08.png) + +
+ +### Recap + +Here are two important things to remember from this unit: + +- Launch configurations are used to specify attributes such as `name`, `type`, +`request`, `preLaunchTask`, `program`, and `console`. +- Developers can edit a launch configuration to accommodate project +requirements. + +--- diff --git a/033_Debug_console_apps_2/ejm_debug/Program.cs b/033_Debug_console_apps_2/ejm_debug/Program.cs new file mode 100644 index 0000000..dd50534 --- /dev/null +++ b/033_Debug_console_apps_2/ejm_debug/Program.cs @@ -0,0 +1,28 @@ +// This code uses a names array and corresponding methods to display +// greeting messages + +string[] names = { "Sophia", "Andrew", "AllGreetings" }; +string msg_txt = ""; + +for (int i = 0; i < names.Length; i++){ + string name = names[i]; + if (name == "Sophia") + msg_txt = sophia_msg(); + else if (name == "Andrew") + msg_txt = andrew_msg(); + else if (name == "AllGreetings") + msg_txt = sophia_msg(); + msg_txt = msg_txt + "\n\r" + andrew_msg(); + Console.WriteLine(msg_txt + "\n\r"); +} + +bool pauseCode = true; +while (pauseCode == true); + +static string sophia_msg() { + return "Hello, my name is Sophia."; +} + +static string andrew_msg() { + return "Hi, my name is Andrew. Good to meet you."; +} diff --git a/033_Debug_console_apps_2/ejm_debug/ejm_debug.csproj b/033_Debug_console_apps_2/ejm_debug/ejm_debug.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/033_Debug_console_apps_2/ejm_debug/ejm_debug.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/033_Debug_console_apps_2/img/code_oss_debug_01.png b/033_Debug_console_apps_2/img/code_oss_debug_01.png new file mode 100644 index 0000000..df7d89f Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_01.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_02.png b/033_Debug_console_apps_2/img/code_oss_debug_02.png new file mode 100644 index 0000000..6a02a70 Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_02.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_03.png b/033_Debug_console_apps_2/img/code_oss_debug_03.png new file mode 100644 index 0000000..ce6e5bd Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_03.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_04.png b/033_Debug_console_apps_2/img/code_oss_debug_04.png new file mode 100644 index 0000000..c375a98 Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_04.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_05.png b/033_Debug_console_apps_2/img/code_oss_debug_05.png new file mode 100644 index 0000000..5900287 Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_05.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_06.png b/033_Debug_console_apps_2/img/code_oss_debug_06.png new file mode 100644 index 0000000..4373906 Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_06.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_07.png b/033_Debug_console_apps_2/img/code_oss_debug_07.png new file mode 100644 index 0000000..1e88374 Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_07.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_08.png b/033_Debug_console_apps_2/img/code_oss_debug_08.png new file mode 100644 index 0000000..89b952a Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_08.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_panel.png b/033_Debug_console_apps_2/img/code_oss_debug_panel.png new file mode 100644 index 0000000..c51dc10 Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_panel.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debug_toolbar.png b/033_Debug_console_apps_2/img/code_oss_debug_toolbar.png new file mode 100644 index 0000000..14243ee Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debug_toolbar.png differ diff --git a/033_Debug_console_apps_2/img/code_oss_debuger.png b/033_Debug_console_apps_2/img/code_oss_debuger.png new file mode 100644 index 0000000..fb26ba0 Binary files /dev/null and b/033_Debug_console_apps_2/img/code_oss_debuger.png differ diff --git a/README.md b/README.md index 3ad3f23..8483916 100644 --- a/README.md +++ b/README.md @@ -36,4 +36,5 @@ Following 29. [Methods that return values](./029_return_value_method/029_csharp.md) 30. [Guided project - Plan a Petting Zoo](./030_project_petting_zoo/030_csharp.md) 31. [Challenge project - Create a mini-game](./031_Challenge_mini_game/031_csharp.md) -32. [Debug console applications](./032_Debug_console_apps/032_csharp.md) +32. [Debug console applications 1](./032_Debug_console_apps/032_csharp.md) +32. [Debug console applications 2](./032_Debug_console_apps_2/033_csharp.md)