2

Debugging Dapr Solutions

In this chapter, you will learn how to set up your local development environment in Visual Studio Code (VS Code) to locally debug simple Distributed Application Runtime (Dapr) solutions, as well as more complex ones.

The base concepts of Dapr execution are presented with several different approaches—with the command-line interface (CLI), with a VS Code debug session, and with Tye. Depending on your preferences, you will choose the one that suits you most and adopt it throughout the rest of the book.

This chapter covers the following topics:

  • Configuring VS Code debug for Dapr
  • Debugging a Dapr multi-project solution
  • Using Tye with Dapr

In learning, there is no substitute for practice. Dapr is no exception, and to practice it, we will launch one Dapr application (or many) to investigate how it behaves—the sooner we are able to debug it, the better. We will start by configuring in VS Code.

Technical requirements

The code for this chapter can be found on GitHub at https://github.com/PacktPublishing/Practical-Microservices-with-Dapr-and-.NET-Second-Edition/tree/main/chapter02.

In this chapter, the working area for scripts and code is expected to be <repository path>chapter02. In my local environment, it is C:Repospractical-daprchapter02.

Please refer to the Setting up Dapr section in Chapter 1, Introducing Dapr, for a complete guide to the tools needed to develop with Dapr and work with the samples.

Configuring VS Code debug for Dapr

Throughout this book, we will leverage VS Code in exploring Dapr via several examples. Before we delve into the detailed features of Dapr, we need to understand how VS Code, the multi-platform code editor, can be configured to help us debug our sample code.

For an extended guide on how to set up Dapr debugging in VS Code, see the documentation at https://docs.dapr.io/developing-applications/ides/vscode/vscode-how-to-debug-multiple-dapr-apps/.

The following sections will guide us in configuring debugging in VS Code on a copy of our hello -world sample from the previous chapter.

Attaching the debugger

In the working area of the chapter, you will find the samples from Chapter 1, Introducing Dapr. From Command Prompt, you can launch a sample via the Dapr CLI with the dotnet run command to launch the Web API project, previously modified to accommodate Dapr, as follows:

PS C:Repospractical-daprchapter02sample.microservice.
webapi> dapr run --app-id hello-world --app-port 5000 --dapr-
http-port 5010 dotnet run

You can expect this as the output:

Starting Dapr with id hello-world. HTTP Port: 5010. gRPC Port:
57138
…
Updating metadata for app command: dotnet run
You're up and running! Both Dapr and your app logs will appear here.

Without any additional configuration, other than the default provided by VS Code, we can attach the .NET running code to debug our Dapr sample service.

As we are going to change the debug configurations later, I suggest that we grow accustomed to it.

Here is the default content of the launch.json file for a .NET Web API project—at this stage, we will focus on the .NET Core Attach configuration:

{
   "version": "0.2.0",
   "configurations": [
        {
            "name": ".NET Core Launch (web)",
            "type": "coreclr",
            "request": "launch",
            "preLaunchTask": "build",
            //
            "program": "${workspaceFolder}/bin/Debug/net6.0
              /sample.microservice.webapi.dll",
            "args": [],
            "cwd": "${workspaceFolder}",
            "stopAtEntry": false,
            /* Enable launching a web browser when ASP.NET
            Core starts. For more information: https://aka.ms/
            VSCode-CS-LaunchJson-WebBrowser */
            "serverReadyAction": {
                "action": "openExternally",
                "pattern": "\bNow listening
                   on:\s+(https?://\S+)"
            },
            "env": {
                "ASPNETCORE_ENVIRONMENT": "Development"
            },
            "sourceFileMap": {
                "/Views": "${workspaceFolder}/Views"
            }
        },
        {
            "name": ".NET Core Attach",
            "type": "coreclr",
            "request": "attach",
            "processId": "${command:pickProcess}"
        }
    ]
}

In the preceding configuration, there is nothing special, other than asking the end user the process to which to attach the VS Code debugging experience.

Important note: configuration default naming

You will often read the name .NET Core in the configuration files prepared for you in VS Code. It is nothing more than a residue from the past version of .NET, and is not an indication of the .NET version used throughout the project and debug files.

With our Dapr hello-world service running in a Dapr runtime process (daprd.exe) launched via the Dapr CLI, by starting the .NET Core Attach VS Code debugging configuration, we should look for the .NET Web API server process instead. In this context, it can be found as sample.microservice.webapi.exe, as you can see from the following screenshot:

Figure 2.1 – Attaching debug to process in VS Code

Figure 2.1 – Attaching debug to process in VS Code

Once we have selected the right process to attach the debugger to, we should be able to set breakpoints in VS Code and properly debug our code.

This was an easy approach to start with, although it might prove less than optimal with frequent debugging or more complex projects.

Next, we’ll examine the configuration in more detail.

Examining the debug configuration

The next objective is to instruct VS Code to combine both steps: launching Dapr via the CLI and attaching the debugger.

Tip

You can activate the Command Palette in VS Code with the Ctrl + Shift + P keys. For more details on the tool’s user interface (UI), see https://code.visualstudio.com/docs/getstarted/userinterface.

Instead of manually configuring launch.json, we can leverage the Dapr extension for VS Code to scaffold the configuration for us.

In our hello-world sample, let’s open the Command Palette and look for Dapr tasks. Among these, we can find Dapr: Scaffold Dapr Tasks, as illustrated in the following screenshot:

Figure 2.2 – Tasks in the Dapr extension for VS Code

Figure 2.2 – Tasks in the Dapr extension for VS Code

By selecting it, we get asked which launch base configuration to derive from: the default .NET Core Launch (web) is the one to choose.

To stay consistent with our direct usage of the Dapr CLI, we set hello-world as the app identifier (ID) and leave the port at the default app-port 5000. The following extract of launch.json displays the relevant changes:

{
   "version": "0.2.0",
   "configurations": [
    {
        "name": ".NET Core Launch (web)",
        … omitted …
    },
    {
        "name": ".NET Core Attach",
        … omitted …
    },
    {
        "name": ".NET Core Launch (web) with Dapr",
        "type": "coreclr",
        "request": "launch",
        "preLaunchTask": "daprd-debug",
        "program": "${workspaceFolder}/bin/Debug/net6.0
            /sample.microservice.webapi.dll",
        "args": [],
        "cwd": "${workspaceFolder}",
        "stopAtEntry": false,
        "serverReadyAction": {
            "action": "openExternally",
            "pattern": "\bNow listening
              on:\s+(https?://\S+)"
        },
        "env": {
            "ASPNETCORE_ENVIRONMENT": "Development"
        },
        "sourceFileMap": {
            "/Views": "${workspaceFolder}/Views"
        },
        "postDebugTask": "daprd-down"
    }
   ]
}

A tasks.json file has also been prepared by the Dapr extension task, and this can be viewed here:

{
    "version": "2.0.0",
    "tasks": [
        … omitted …
        {
            "appId": "hello-world",
            "appPort": 5000,
            "label": "daprd-debug",
            "type": "daprd",
            "dependsOn": "build"
        },
        {
            "appId": "hello-world",
            "label": "daprd-down",
            "type": "daprd-down"
        }
    ]
}

Once we activate debugging in VS Code by selecting the .NET Core Launch (web) with Dapr configuration, this is what happens, in order:

  1. A "daprd-debug" task is invoked.
  2. This task has a dependency on the "build" task, which, as the name implies, builds the .NET project.
  3. The newly built .NET Web API project is executed.
  4. The task has the type "daprd": the Dapr debugger is invoked with the configured settings.
  5. Once we are done with debugging, the "dapr-down" task is invoked to stop the Dapr service.

Tip

Keep in mind that the VS Code debug configuration is an alternative approach to launching via the Dapr CLI: on a development environment, you cannot have multiple processes trying to run the same application ID with port numbers already in use.

I recommend that you explicitly edit the task in task.json to accommodate the local development environment needs.

To match the dapr run –app-id hello-world –app-port 5000 –dapr-http-port 5010 dotnet run Dapr CLI syntax we’ve used so far, appPort is the port used by the .NET Web API application, while httpPort and grpcPort are configured to expose Dapr endpoints. You can see these ports in the following code snippet:

{
    "appId": "hello-world",
    "appPort": 5000,
    "httpPort": 5010,
    "grpcPort": 50010,
    "label": "daprd-debug",
    "type": "daprd",
    "dependsOn": "build"
}

If we launch the VS Code debug configuration, here is the terminal output, showing the expected steps:

> Executing task: C:Program Filesdotnetdotnet.exe
build C:Repospractical-daprchapter02
sample.microservice.webapi/sample.microservice.
webapi.csproj /property:GenerateFullPaths=true/
consoleloggerparameters:NoSummary <
Microsoft (R) Build Engine version 17.0.0+c9eb9dd64 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
  Restore completed in 49,91 ms for C:Repospractical-dapr
  chapter02sample.microservice.webapisample.microservice.
  webapi.csproj.
  sample.microservice.webapi -> C:Repospractical-dapr
  chapter02sample.microservice.webapiinDebug
et6.0sample.
  microservice.webapi.dll
Terminal will be reused by tasks, press any key to close it.
> Executing task: daprd-debug <
> Executing command: daprd –app-id "hello-world" –app-port 
  "5000" –dapr-grpc-port "50010" –dapr-http-port "5010" –
  placement-address "localhost:50005" <

The latest command shows how the debug configuration is leveraging the Dapr CLI with the exact ports and settings we specified for task.json.

By reaching Dapr at http://localhost:5010/v1.0/invoke/hello-world/method/hello, we received the expected results, this time in an integrated debugging experience inside of VS Code.

We have now successfully configured VS Code to be able to rapidly build our .NET project, start Dapr with our configuration, and clean up at the end. So, we’ll do all that in the coming sections.

Debugging a Dapr multi-project solution

In this section, we will configure debugging for multiple ASP.NET projects. In most cases, a .NET solution is developed in different projects, each representing a microservice or another component of the overall architecture. This is even more true in Dapr, which emphasizes and facilitates the development of microservices.

In this context, we leverage the VS Code capability to debug multiple projects at once. For more details, see the documentation at https://code.visualstudio.com/docs/editor/debugging#_multitarget-debugging.

When we previously needed to launch with only one project, we leveraged a scaffold task in the VS Code Dapr extension to add Dapr support in the launch.json and task.json files.

This time, we will create a new .NET project and include both in a solution. Afterward, we will manually edit the debug configuration files.

Creating .NET solutions

We previously provisioned our first .NET project. To test the multi-project debug configuration, we’ll add a second Dapr project to our environment—in a great feat of imagination, let’s name it sample.microservice.webapi2, as follows:

PS C:Repospractical-daprchapter02sample.microservice.
  webapi> cd ..
PS C:Repospractical-daprchapter02> dotnet new webapi -o
  sample.microservice.webapi2
The template "ASP.NET Core Web API" was created successfully.
Processing post-creation actions…
Running 'dotnet restore' on sample.microservice.webapi2sample.
  microservice.webapi2.csproj...
  Restore completed in 152,92 ms for C:Repospractical-dapr
  chapter02sample.microservice.webapi2
  sample.microservice.webapi2.csproj.
Restore succeeded.

For brevity, the newly created .NET project should receive the same changes we applied to our first sample in the Building our first Dapr sample section of Chapter 1, Introducing Dapr.

With two ASP.NET projects, we could use a solution file to combine them—the .NET CLI has the ability to create an empty .sln file and add projects to it, as we can see here:

PS C:Repospractical-daprchapter02> dotnet new sln
The template "Solution File" was created successfully.
PS C:Repospractical-daprchapter02> dotnet sln add c:Repos
practical-daprchapter02sample.microservice.webapisample.
microservice.webapi.csproj

The solution file is ready; we can now prepare the debugging configuration.

Launching the configuration

As we intend to debug sample.microservice.webapi (our original project) and sample.microservice.webapi2 at the same time, the two .NET projects and the Dapr application need to be running at the same time.

It is required that each ASP.NET project is hosted on a different port and that each Dapr application has a different name and a unique HyperText Transfer Protocol (HTTP), gRPC Remote Procedure Call (gRPC), and metrics port, and should refer to the ASP.NET port as the Dapr app port.

The following code is a portion of the launch.json file:

… omitted …
    "configurations": [
     {
         "name": ".NET Core Launch w/Dapr (webapi)",
         … omitted …
     },
     {
        "name": ".NET Core Launch w/Dapr (webapi2)",
        "type": "coreclr",
        "request": "launch",
        "preLaunchTask": "daprd-debug-webapi2",
        "program": "${workspaceFolder}/sample
            .microservice.webapi2/bin/Debug
            /net6.0/sample.microservice.webapi2.dll",
        "args": [],
        "cwd": "${workspaceFolder}
            /sample.microservice.webapi2",
        "stopAtEntry": false,
        "env": {
            "ASPNETCORE_ENVIRONMENT": "Development",
            "ASPNETCORE_URLS": "http://+:5002",
            «DAPR_HTTP_PORT»: «5020»
        },
        "sourceFileMap": {
            "/Views": "${workspaceFolder}/Views"
        },
        "postDebugTask": "daprd-down-webapi2"
    }
]
… omitted …

As you can see from the launch configurations, each one refers to a corresponding preLaunchTask task and a postDebugTask task.

The DAPR_HTTP_PORT and ASPNETCORE_URLS environment variables match the configuration in the task.json file.

Tasks

Here is an extract from the tasks:[…] element in the task.json file. You can find the complete configuration file in the sample directory:

… omitted …
      {
          "label": "build-webapi",
          "command": "dotnet",
          "type": "process",
          "args": [
              "build",
              "${workspaceFolder}/sample
                  .microservice.webapi
                  /sample.microservice.webapi.csproj",
              "/property:GenerateFullPaths=true",
              "/consoleloggerparameters:NoSummary"
            ],
            "problemMatcher": "$msCompile"
        },
        {
            "appId": "hello-world",
            "appPort": 5001,
            "httpPort": 5010,
            "grpcPort": 50010,
            "metricsPort": 9091,
            "label": "daprd-debug-webapi",
            "type": "daprd",
            … omitted …
            },
            "dependsOn": "build-webapi"
        },
        {
            "appId": "hello-world",
            "label": "daprd-down-webapi",
            "type": "daprd-down"
        }
… omitted …

In the previous snippet, you can see that for the hello-world service, corresponding to the sample.microservice.webapi project, the configuration adopts a set of "appPort": 5001, "httpPort": 5010, "grpcPort": 50010, and "metricsPort": 9091. The latter metrics endpoint is useful if you want to test Prometheus in your local development machine, as documented at https://docs.dapr.io/operations/monitoring/metrics/prometheus/#setup-prometheus-locally. In Chapter 11, Tracing Dapr Applications, we will learn more about this topic.

By contrast, the salute-world service configuration adopts other non-conflicting ports for the appPort, httpPort, grpcPort, and metricsPort settings.

It is worth noting that in the configuration file, two sets of tasks for build, dapr-debug (which launches the Dapr app), and dapr-down (to stop and clean up) have been created, one for each project.

I also had to edit the path to each project’s folder with the "${workspaceFolder}/<project path>/<file>" pattern wherever a reference to the project’s file or library was needed.

Launching debug sessions individually

With these configurations, we can individually launch the integrated .NET and Dapr debugging experience in VS Code for each project. In the following screenshot, you can see the two debug configurations being recognized in VS Code:

Figure 2.3 – Debug launch configurations in VS Code

Figure 2.3 – Debug launch configurations in VS Code

We can test that each project is properly built and gets exposed (locally) as an ASP.NET endpoint, and then a Dapr CLI debugger is launched for each application.

As a simple test, in the following snippet, let’s invoke the two Dapr applications via curl while they are in debugging mode in VS Code:

PS C:> curl http://localhost:5010/v1.0/invoke/hello-world/
  method/hello
Hello, World
PS C:> curl http://localhost:5020/v1.0/invoke/salute-world/
  method/salute
I salute you, my dear World.

Our first two sample Dapr services can be invoked via the Dapr runtime. Now let’s try to launch a compound debug session next.

Launching compound debug sessions

We are not done yet: our last objective is to instruct VS Code to build and launch the two Dapr applications at the same time, instead of having the user individually launch the configuration for each project. This can be achieved with a compound task in VS Code. You can visit https://code.visualstudio.com/docs/editor/debugging#_compound-launch-configurations for more information.

A compound launch configuration starts multiple debug sessions in parallel. All we need to do is refer to the previously defined configurations in launch.json, as follows:

"compounds":
   [
     {
       "name": "webApi + webApi2 w/Dapr",
       "configurations": [".NET Core Launch w/Dapr
         (webapi)", ".NET Core Launch w/Dapr (webapi2)"]
     }
   ]

As we can see from the following screenshot, we have both of the VS Code debug sessions active, and both of the Dapr applications we previously defined, hello-world and salute-world, are active:

Figure 2.4 – A Dapr debug session in VS Code

Figure 2.4 – A Dapr debug session in VS Code

As the Dapr applications have been launched from the Dapr CLI debugger, they appear in the context of the Dapr extension for VS Code, as shown in Figure 2.4, but they do not show up in the Dapr CLI; the dapr list command and the Dapr dashboard will show no applications running.

This completes our mission: we are now able to quickly enter a debug session that encompasses all the projects for the microservices and other libraries we need.

In the next section, we will learn about a new, exciting project in the .NET space that can help us improve the debugging experience with Dapr.

Using Tye with Dapr

I find the multi-target debugging provided by VS Code a rewarding experience for Dapr solutions with several projects; nevertheless, there are always many options to accomplish the same task. One option for this particular task is Tye.

A new open source initiative by the .NET Foundation, Project Tye, is currently under development as an experimental project. For more information, check out the documentation at https://github.com/dotnet/tye/blob/master/docs/.

Project Tye is a tool to make developing, testing, and deploying microservices and distributed applications easier. In the upcoming sections, we will explore Project Tye in conjunction with Dapr.

Installing Tye

At the time of writing, 0.10.0 is the latest public version of Tye. With the following command, you can install it in your environment:

PS C:Repospractical-daprchapter02> dotnet tool install -g
  Microsoft.Tye --version "0.10.0-alpha.21420.1"
You can invoke the tool using the following command: tye
Tool 'microsoft.tye' (version '0. 10.0-alpha.21420.1') was
  successfully installed.

It’s that simple! Tye is now ready to be configured in our .NET solution.

Using Tye

In the root folder of the project structure, we initialize the .yaml file to instruct Tye on how to deal with the ASP.NET projects and Dapr configurations, as follows:

PS C:Repospractical-daprchapter02> tye init
Created 'C:Repospractical-daprchapter02	ye.yaml'.
Time Elapsed: 00:00:00:34

The preceding command creates a tye.yaml file with the following content:

name: hello-world-debug
services:
- name: dapr-microservice-webapi
  project: sample.microservice.webapi/sample.microservice.
  webapi.csproj
- name: dapr-microservice-webapi2
  project: sample.microservice.webapi2/sample.microservice.
  webapi2.csproj

As I already had a solution file, Tye recognized the presence of the two projects. In our previous samples, we used two different Dapr app-id instances: hello-world and salute-world; we will fix this in the next step.

By mutating the Dapr recipe from the Tye repository at https://github.com/dotnet/tye/blob/main/docs/recipes/dapr.md, I changed the default configuration to the following:

name: hello-world-debug
extensions:
- name: dapr

The only change has been adding extensions with name: dapr.

A caveat: as I already initialized Dapr on my local environment, Redis is already in place. Therefore, I left it out of the Tye configuration by commenting it.

From the command line (Windows Terminal or a VS Code terminal window), we can launch Tye with the tye run command, as follows:

PS C:Repospractical-daprchapter02> tye run

From the following output, we can see how Tye launches our Dapr applications:

Loading Application Details...
Launching Tye Host...
[21:23:05 INF] Executing application from C:Repospractical-
daprchapter02	ye.yaml
[21:23:05 INF] Dashboard running on http://127.0.0.1:8000
[21:23:06 INF] Building projects
[21:23:07 INF] Launching service hello-world-dapr_dc1ac8cb-5:
daprd -app-id hello-world -app-port 60146 -dapr-grpc-port 60150
--dapr-http-port 60151 --metrics-port 60152 --placement-address
localhost:50005 -log-level debug
[21:23:07 INF] Launching service hello-world_613eee7d-f: C:
Repospractical-daprchapter02sample.microservice.webapiin
Debug
et5.0sample.microservice.webapi.exe
[21:23:07 INF] Launching service salute-world-dapr_90068b8d-4:
daprd -app-id salute-world -app-port 60148 -dapr-grpc-port 60153 --dapr-http-port 60154 --metrics-port 60155 --placement-
address localhost:50005 -log-level debug
… omitted …

From the command output, we can observe that Tye launches the Dapr CLI debugger (daprd), referring to the corresponding Dapr application for the ASP.NET project, all by providing dynamic ports.

The Tye tool offers a portal from which you can access useful .NET metrics about the running processes, as illustrated in the following screenshot:

Figure 2.5 – The Tye portal

Figure 2.5 – The Tye portal

In Figure 2.5, you can see the Tye portal showing our Dapr services and the corresponding Dapr sidecars.

The –-debug * option of the Tye command waits for VS Code debug sessions to be attached to each service: in the Tye portal logs, you will see a Waiting for debugger to attach... message.

In VS Code, we can leverage the .NET Core Attach debug configuration, by selecting the corresponding ASP.NET process (as we did at the beginning of this chapter) for each of our sample projects.

You might consider the option to customize the .NET Core Attach VS Code configuration to provide support for multiple projects, similar to what we did previously with the .NET Core Launch w/Dapr (webapi) debug configuration.

Once the VS Code debug session has started, we can invoke our Dapr applications, as follows:

PS C:> curl http://localhost:60151/v1.0/invoke/hello-world/
  method/hello
Hello, World

The first Dapr service responded; next, we test the second one, as follows:

PS C:> curl http://localhost:60154/v1.0/invoke/salute-world/
  method/salute
I salute you, my dear World.

The Tye tool is useful in the context of both debugging .NET solutions and deploying them. Its integration with Dapr greatly simplifies the debugging experience.

With Tye, we have completed our discussion of Dapr’s debugging options.

Summary

In this chapter, you have learned how to take advantage of several available options to debug C# Dapr projects, leveraging VS Code’s debug capabilities and configurations, the Dapr CLI itself, and Project Tye.

Getting comfortable with Tye and the Dapr CLI is also important, as these will be the most frequently used approaches to launch our Dapr application in the testing phase.

In the next chapter, we will explore in more depth how services are invoked within Dapr.

Questions

  1. How do you scaffold debugging for Dapr in VS Code?
  2. How do you compound the debug configuration for multiple Dapr projects?
  3. How do you attach to a running Dapr application with VS Code?
  4. How do you configure the Dapr components in Tye?

Further reading

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.91.239