Skip to content

A repository to show how to debug .NET lambda functions running in LocalStack

License

Notifications You must be signed in to change notification settings

localstack-samples/lambda-dotnet-debugging

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lambda .NET debugging using Visual Studio Code

This sample shows how to debug .NET Lambda functions using Visual Studio Code.

Usage

This section will showcase the usage of this sample, and explain the steps necessary to make .NET Lambda debugging work.

Prerequisites

This guide assumes that you have Visual Studio Code installed, with the Docker and C# Dev Kit extensions.

We also expect the following tools being installed:

Installation of vsdbg

We need to install the visual studio .NET debugger vsdbg into a local directory to allow it to be mounted into our Lambda containers.

The VS Code C# extension wiki page uses an installation script for this (see here), and so will we.

Using the following command, we will install the latest version in the linux-x64 version into the ./vsdbg directory of this folder:

Note

In general, we do not recommend piping the output of curl directly into a shell process. For illustration purposes, we will do this in this guide, please download the script manually and check it before running it on your machine.

curl -sSL https://aka.ms/getvsdbgsh | /bin/sh /dev/stdin -v latest -r linux-x64 -l ./vsdbg

Alternatively, you can execute the download-vsdbg.sh script, performing the exact same action. This will also be done using the make install command, in addition to downloading other dependencies.

Starting LocalStack (Pro)

The docker-compose.yml file in this repository is already configured to mount the ./vsdbg directory into all spawned Lambda containers.

Please set your LOCALSTACK_AUTH_TOKEN and run docker compose up to start LocalStack.

Deploying our TestStack

In our test-stack directory, we prepared a simple CDK stack to deploy an .NET lambda (its code can be found in the lambda-code directory).

This stack contains an API Gatway REST API with a Lambda proxy integration to our .NET lambda.

To deploy it, please go to the test-stack directory.

cdklocal bootstrap
cdklocal deploy --require-approval "never"

This will build the .NET Lambda function and deploy it - and the rest of the stack - on LocalStack.

Specifics of building the .NET Lambda

As seen in the stack definition, we need to build the lambda using the Debug configuration.

Please add --configuration Debug to the dotnet lambda command packaging the Lambda code archive, when trying to enable debugging on existing projects.

Configuring VS Code

This repository contains the a VS Code launch.json and tasks.json configuration in the lambda-code/.vscode directory.

This configurations are already set up to attach to running processes, and you can use them by starting VS Code in the lambda-code/ directory.

In the rest of this section we will explain the configuration.

Let us take another look into the important part of the launch.json file, this time annotated with more context:

    "configurations": [
        {
            "name": "Attach to .NET Lambda",
            "type": "coreclr",
            "request": "attach",
            "sourceFileMap": {
                // This mapping is necessary, as the deployment package is built in this folder inside the CDK build container.
                "/asset-input": "${workspaceFolder}/src"  
            },
            // This part allows VS Code to communicate with the debugger running in docker
            "pipeTransport": { 
                "pipeCwd": "${workspaceFolder}",
                "pipeProgram": "docker",
                "quoteArgs": false,
                "pipeArgs": [
                    "exec",
                    "-i",
                    "-u",
                    // We need to execute the debugger as the same user as the Lambda is running - per default this is `sbx_user1051`.
                    "sbx_user1051", 
                    // Select the target container to debug
                    "${command:vscode-docker.containers.select}",
                ],
                // Path to the debugger inside the Lambda container, we mount it using the `LAMBDA_DOCKER_FLAGS` in our docker compose file
                "debuggerPath": "/vsdbg/vsdbg"  
            },
            // We need to install some dependencies inside the container before we can start the debugging process
            "preLaunchTask": "init-container" 
        }
    ]

The preLaunchTask refers to the following task inside our tasks.json:

{
    "label": "init-container",
    "command": "docker",
    "type": "process",
    "args": [
        "exec",
        // select the target container
        "${command:vscode-docker.containers.select}",
        "dnf",
        "install",
        "-y",
        // install `xargs` and `ps`
        "findutils",
        "procps"
    ]
}

The init-container task installs two packages into the Lambda container, to allow usage of the xargs and ps tools necessary by the process selection of the VS Code .NET debugger.

Attaching the debugger

To allow attaching our debugger to the running .NET process, we need to start the Lambda once, as we can only attach to running processes.

We do this by invoking the API Gateway endpoint (please replace <api_id> with the APIGateway ID returned by the cdklocal deploy step):

curl https://<api_id>.execute-api.localhost.localstack.cloud:4566/prod/

Before continuing to debug, let's set a breakpoint in VS Code, so we can actually observe the outcome. For demonstration purposes, let's choose the Console.WriteLine statement here:

Console.WriteLine("Test debug print");

Once the container is running, we can select the Run and Debug menu in VS Code, and select the "Attach to .NET Lambda" configuration.

VS Code will now prompt us to select the container twice, we need to choose the same container twice. LocalStack Lambda container names include the function name, which we can use to choose the right container.

After a short installation step, we now select the "dotnet" process, usually marked as such, to attach the debugger.

Another invocation of the API Gateway endpoint should trigger a halt at the selected breakpoint correctly.

Known Limitations

There are some limitations with this approach to debugging .NET Lambda functions.

The target container needs to be selected twice

We currently have to select the Lambda function twice, once for the preLaunchTask, and then again to connect to the container for debugging.

Sadly, VS Code currently does not allow passing inputs to a preLaunchTask, so we could reuse the selection.

However, you can build your own Lambda images containing those packages, and push them to an internal docker registry. To enable this, please take a look into the LAMBDA_RUNTIME_IMAGE_MAPPING configuration, as described in our documentation.

You need to install the findutils and procps packages using dnf install -y findutils procps to enable proper functioning of the debugger.

The Lambda function needs to be invoked once before attaching

Per design, we can only attach to running processes with the .NET debugger. This leads to the requirement to execute the Lambda function at least once to attach a debugger.

A future solution could involve something similar to provisioned concurrency, but the node process is currently not started in this case using LocalStack.

About

A repository to show how to debug .NET lambda functions running in LocalStack

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published