Skip to content

Latest commit

 

History

History
 
 

csharp-example-extension

Example Extension in C#.NET

The provided code sample demonstrates how to get a basic extension written in C# up and running.

Project structure

Project files and folders:

  • csharp-example-extension.csproj - .NET Core project file, which is mandatory for .NET Core build process. It defines <LangVersion>latest</LangVersion>, so that the latest C# language features, like async Main could be used.
  • Program.cs - main entry point for this extension.
  • ExtensionClient.cs - Lambda Extension API client implementation.
  • ExtensionEvent.cs - Event types enumerable, so that the rest of the code can work with enum values, rather than string constants.
  • extensions/csharp-example-extension - Bash script that must be deployed to opt/extensions folder as an executable file (see manual deployment steps below for details). This script will be used for .NET runtime dependent deployment.
  • extensions/csharp-example-extension-self-contained - Bash script that must be deployed to opt/extensions folder as an executable file (see manual deployment steps below for details). This script will be used for self-contained deployment.

Requirements

  • .NET Core SDK - 5.0 or a later version with 3.1 targeting pack installed (if .NET Core 3.1 dependent deployment is used).
  • AWS CLI v2 - version 2.1.14 or newer.
  • Since this is an external .NET Core extension, we would require a lambda function with .NET Core 3.1 runtime published to test this extension. For more information on publishing a blank C# lambda function please refer here.
  • Bash shell with zip command support. Linux and macOS operating systems have that shell available by default (although the macOS has recently switched to ZSH default shell, Bash is still available for Catalina and Big Sur anyway). Windows 10 users can install Windows Subsystem for Linux or just use Git Bash, which is included with Git for Windows installation package.

The following configuration setting must be set in AWS CLI configuration file (~/.aws/config), so that AWS CLI v2 will use backward compatibility with the AWS CLI version 1 behavior where binary values must be passed literally:

cli_binary_format=raw-in-base64-out

Setup

Clone the repository

git clone https://github.com/aws-samples/aws-lambda-extensions.git
cd aws-lambda-extensions/csharp-example-extension

Deployment options

csharp-example-extension.csproj has all necessary configuration for deploying this extension as a self-contained executable or a .NET runtime dependent extension. Self-contained executable does not require any runtime to be pre-installed for Lambda function, thus it is compatible with any Lambda functions (.NET, Java, NodeJS, etc.). All necessary .NET runtime libraries are packaged together with the extension, thus the result package is much larger, than the .NET runtime dependent package (10MB+ vs 10KB+).

Automated deployment: Use shell script to deploy the extension

  • make sure that csharp-example-extension is your current folder and run.sh script has executable bit set - ls -l run.sh output should start with -rwxr-xr-x permissions mask.
  • make run.sh executable with chmod +x run.sh if needed.
  • assuming that demo C# Lambda function has already been deployed to the current AWS account and its name is test-dotnet, execute the following command to build the extension and deploy it to the current AWS account as a Lambda layer, named csharp-example-extension:

.NET Core 3.1 dependent extension

IMPORTANT: You will be able to attach this extension to .NET Core 3.1 Lambda functions only!!!

./run.sh -e csharp-example-extension -f test-dotnet

Self-contained extension

This type of deployment is compatible with any Lambda function runtime.

./run.sh -e csharp-example-extension -f test-dotnet -s

Manual deployment

  • Make sure that all scripts in extensions/* folder has executable bit set and set it if needed, otherwise Lambda initialization will fail with PermissionDenied error (see Troubleshooting section for details):
chmod +x extensions/*
  • Publish .NET Core project with Release configuration and targeting a specific framework. csharp-example-extension.csproj file contains all necessary configuration for building and packaging the result if needed. This command (see below) will download all necessary NuGet packages, referenced by the project, build the binaries using Release configuration settings and publish the result to bin/publish folder. Please, refer to dotnet publish documentation for details and additional command line options.

Build runtime dependent extension (compatible with .NET Core 3.1 Lambda only!!!)

dotnet publish -c Release -f netcoreapp3.1 -o bin/publish

Build self-contained extension using .NET Core 5.0 runtime

-p:Platform=x64 switch will enable conditional build configuration in csharp-example-extension.csproj to package extension together with linux-x64 runtime and wrap everything into a single bundle. This bundle doesn't require a custom shell script and will be deployed directly to extensions folder.

dotnet publish -c Release -f net5.0 -p:Platform=x64 -o bin/publish
  • Change your current folder to the publish destination folder:
cd bin/publish
  • Move all publish results to deploy.zip archive recursively:
zip -rm ./deploy.zip *
  • Define Lambda function and extension name variables, so that they can be easily referenced later. Make sure that test-dotnet Lambda function has already been published to the current AWS account (it can be any other, non-.NET function im case of the self-contained extension):
EXTENSION_NAME="csharp-example-extension"
LAMBDA_FUNCTION="test-dotnet"
  • Publish extension archive as a new Lambda layer:
aws lambda publish-layer-version \
  --layer-name "${EXTENSION_NAME}" \
  --zip-file "fileb://deploy.zip"
  • Update test-dotnet Lambda function to use csharp-example-extension layer
aws lambda update-function-configuration \
  --function-name ${LAMBDA_FUNCTION} --layers $(aws lambda list-layer-versions --layer-name ${EXTENSION_NAME} \
  --max-items 1 --no-paginate --query 'LayerVersions[0].LayerVersionArn' \
  --output text)

Testing

You can use AWS Console or AWS CLI to invoke your test function (test-dotnet):

aws lambda invoke \
  --function-name "${LAMBDA_FUNCTION}" \
  --payload '{"payload": "hello"}' /tmp/invoke-result \
  --cli-binary-format raw-in-base64-out --log-type Tail

All logs can be fund in /aws/lambda/test-dotnet Cloudwatch group - both Lambda extension and Lambda function log messages are reported to that group.

Troubleshooting

Execution bit not set on the launch script

Symptoms

EXTENSION Name: csharp-example-extension State: LaunchError Events: [] Error Type: PermissionDenied

Resolution

Validate that execution bit has been properly set on the extension shell script. For example ls -la extensions output should look like (notice x bit set):

-rwxr-xr-x 1 user group 289 Dec 22 15:16 csharp-example-extension

Self-contained deployments must make sure that dotnet publish output has proper executable flag set on the bundle file.