This repository showcases a serverless application using .NET 8 with LocalStack, a fully functional local AWS cloud stack and LocalStack.NET v2.0.0-preview1, a thin wrapper around aws-sdk-net which automatically configures the target endpoints to use LocalStack for your local cloud application development.
The demo consists of two AWS Lambda functions showcasing modern .NET development practices:
- Profile API (.NET 8):
- Create Profile Operation:
- Creates a user profile in the profiles DynamoDB table.
- Decodes and saves a base64 image from the payload to the profile images S3 Bucket.
- Sends a success message to the messages SQS.
- Get Profile Operation:
- Retrieves the user profile from the profiles DynamoDB table.
The Profile API is developed using .NET 8 as a standard AWS Lambda function. Native AOT compilation has been temporarily disabled to focus on testing LocalStack.NET v2.0.0-preview1 compatibility. Native AOT support will be re-enabled in future versions once LocalStack.NET has enhanced Native AOT compatibility.
- Message Handler (.NET 8):
- Processes the success message from the messages SQS.
- Saves the success message to the messages DynamoDB table.
The Message Handler is developed using .NET 8 as a standard AWS Lambda with optimized performance.
- Centralized Package Management: Using Directory.Build.props and Directory.Packages.props for consistent dependency management
- .NET 8: Stable runtime with excellent performance for serverless scenarios
- LocalStack.NET v2.0.0-preview1: Testing the latest preview with AWS SDK v4 compatibility
- Modern AWS SDK v4: Latest AWS SDK packages with improved performance and features
- Future Native AOT Support: Framework prepared for Native AOT when LocalStack.NET compatibility is enhanced
- .NET 8 SDK: Download .NET
- Amazon.Lambda.Tools (.NET global tool): Amazon.Lambda.Tools on NuGet. Install using the command:
dotnet tool install --global Amazon.Lambda.Tools --version 5.10.0
. This tool allows you to pack and deploy a Lambda function from the command line in the Lambda function's project root directory. It is used by the deploy scripts. - Docker and docker-compose: We use Docker to run the LocalStack container. Install Docker and docker-compose.
- awslocal CLI: awslocal CLI on GitHub. It's a thin wrapper around the AWS command line interface for use with LocalStack.
- AWS CLI: Install AWS CLI. This is used by the deploy scripts.
- For Mac/Linux:
jq
andzip
LocalStack is a fully functional local AWS cloud stack. While it can be installed directly on your machine and accessed via the
localstack
CLI, the recommended approach is to run LocalStack using Docker or docker-compose. For this demo, we've provided adocker-compose
file to easily run LocalStack, but there are other methods to install and run it as well. For detailed installation and setup instructions for LocalStack, please refer to the official LocalStack installation guide.
The entire demo application, including all the provided scripts, is designed to work seamlessly with both LocalStack and real AWS environments. When executing a script (details on scripts are provided in subsequent sections), you'll be prompted to select your deployment target. Simply choose 'aws' to deploy to your actual AWS account. Ensure you have the necessary AWS credentials and configurations set up before deploying to AWS.
- Run LocalStack: Start LocalStack by executing the
docker-compose up
command. - Restore packages: Run
dotnet restore
to restore all NuGet packages using centralized package management. - Deployment Scripts: Use the deployment scripts
deploy.ps1
(for Windows) ordeploy.sh
(for Linux/Mac) to deploy the application. These scripts offer a series of prompts to guide you through the deployment process:- Deployment Target: Choose between deploying to LocalStack or AWS.
- AWS Profile: If deploying to AWS, you'll be prompted to provide an AWS profile.
- Operation Selection: Decide between creating (
deploy
) or deleting (cleanup
) the AWS resources. If you opt for cleanup, you'll receive a confirmation prompt to ensure you want to delete all resources. - Repackaging Lambda Functions: If existing packaged Lambda functions are detected, you'll be asked whether you want to repackage them or use the existing packages.
- Lambda Function Updates: If Lambda functions already exist, you'll be prompted to decide if you want to update them.
The project uses modern .NET development practices:
- Centralized Package Management: All package versions are managed in
Directory.Packages.props
- Common Build Properties: Shared settings in
Directory.Build.props
- Multi-targeting: Core library supports both .NET 8 and .NET 9
- SDK Configuration:
global.json
ensures consistent .NET SDK version (.NET 9 for latest tooling)
You can manually test the ProfileApi using the provided JSON files located in scripts/testdata
. Files prefixed with profile
contain valid payloads and will yield a success response, while those prefixed with invalid
contain invalid payloads and will result in a bad request.
Example commands:
awslocal lambda invoke --function-name profile-service-demo --payload fileb://./scripts/testdata/profile1.json response.json --log-type Tail
awslocal lambda invoke --function-name profile-service-demo --payload fileb://./scripts/testdata/invalid1.json response.json --log-type Tail
The API response will be written to response.json
file. You can extract the value of the id field from this file, update the getprofile.json
file with this ID, and then use the following command to retrieve the saved user:
awslocal lambda invoke --function-name profile-service-demo --payload fileb://./scripts/testdata/getprofile.json response.json --log-type Tail
Under the scripts
folder, you'll find loadtest.ps1
and loadtest.sh
. These scripts will prompt you to choose between LocalStack or AWS for testing. They send randomly generated payloads to the Profile API. Approximately 10% of the requests are invalid, allowing you to observe the behavior of invalid requests. The results of the load tests are written to aggregated_responses.json
.
For manual testing and verification, you can use the following commands to check if the resources have been correctly created in LocalStack:
- List all Lambdas:
awslocal lambda list-functions
- List all S3 buckets:
awslocal s3api list-buckets
- List all SQS queues:
awslocal sqs list-queues
- List all DynamoDB tables:
awslocal dynamodb list-tables
- List all items in DynamoDB:
awslocal dynamodb scan --table-name <TABLE_NAME>
- List all messages in SQS:
awslocal sqs receive-message --queue-url <QUEUE_URL>
- List all files in an S3 bucket:
awslocal s3 ls s3://<BUCKET_NAME>/
These commands are useful to ensure that the resources are set up correctly and to verify the state of your application in LocalStack.
Notes:
- These scripts can also be used with actual AWS. Simply replace
awslocal
withaws
and add your profile to the command--profile <profile-name>
.- When conducting tests, it's beneficial to have
docker stats
running in a separate terminal. This allows you to observe the Lambda containers in action.
This demo showcases LocalStack.NET v2.0.0-preview1 features:
- AWS SDK v4 Compatibility: Testing compatibility with the latest AWS SDK version
- .NET 8/.NET 9 Support: Full support for modern .NET runtimes
- Enhanced Performance: Improved client initialization and connection handling
- Modern Development Practices: Showcases current best practices for .NET serverless development
- Native AOT Ready: Project structure prepared for Native AOT when LocalStack.NET compatibility is enhanced
Feel free to raise issues or submit pull requests if you find any problems or have suggestions for improvements.