This project provides a working, open source based, AWS Lambda handler skeleton .NET code including deployment with the AWS CDK & a GitHub Actions pipeline.
It is inspired by the Python AWS Lambda Handler Cookbook developed by AWS Hero Ran Isenberg.
Starting a Serverless service can be overwhelming. You are introducing a completely new programming model, and a vastly different way of thinking about applications as opposed to the familiar server based development experience.
There are many examples of 'hello world' Lambda functions, but few that dive into a production-ready serverless application comprised of multiple services and teams.
This project aims to reduce cognitive load and answer these questions for you by providing a skeleton .NET Serverless service template that implements best practices for AWS Lambda, Serverless CI/CD, and the AWS CDK in one template project.
It demonstrates both how you can use .NET and AWS Lambda to build your serverless applications. As well as defining .NET applications with the AWS CDK that fully leverage native service integrations, without a single line of code running in production.
- A stock price service that allows users to update the stock price for a given stock, and retrieve the current stock price as well as the history
- The Stock Price service splits queries and commands into seperate functions. All GET endpoints are serviced by a single Lambda function that uses native AOT compilation for performance. Commands run as single purpose Lambda functions
- A notification service that allows users to subscribe to notifications when a given stock price changes
- The notification service demonstrates how to build applications using the AWS CDK without using Lambda functions. It leverages services like Step Functions and Event Bridge Pipes to meet application use cases
- .NET Serverless service with a recommended file structure, following the hexagonal architecture pattern
- Demonstrates native ahead of time (AoT) compilation and the right places to introduce it
- Asynchronous integration between multiple bounded contexts
- CDK infrastructure with unit, integration and functional tests.
- CI/CD pipelines based on Github actions that deploys to AWS.
- The AWS Lambda handler embodies Serverless best practices for a proper production ready handler.
- AWS Lambda handler uses AWS Lambda Powertools{:target="_blank" rel="noopener"} as well as the Lambda Annotations Framework
- Features flags and configuration based on AWS AppConfig
- Building application functionality without using Lambda functions, leveraging managed services and native AWS service integrations
The handler implements multiple best practice utilities.
Each utility is implemented when a new blog post is published about that utility.
The utilities cover multiple aspect of a production-ready service, including:
- Logging
- Observability: Monitoring and Tracing
- Observability: Business KPIs Metrics
- Environment Variables
- Dynamic Configuration & feature flags
- Enabling Multiple Developers to work in the same account using postfixed stacks
Head over to the complete project documentation pages at GitHub pages at https://jeastham1993.github.io/aws-lambda-dotnet-handler-cookbook
You can deploy this sample application into your own AWS account using the AWS CDK. In the future, this example will contain examples for the AWS CDK, AWS SAM, Terraform and Pulumi.
You can also include a 'postfix' as part of your deployment, enabling multiple instances of the same stack to be deployed to the same AWS account.
The project contains shared authentication infrastructure that needs to be deployed first. The StockPrice Application is also deployed independently to the feature flags, allowing features to be changed without an entire application deployment.
If this is your first time deploying, you will need to deploy the CDK projects in the below order. After the first deployment, any order is ok.
# Optionally set a postfix
# export STACK_POSTFIX="-je"
cdk deploy AuthenticationStack<POSTFIX> --require-approval=never --app "dotnet run --project cdk/src/Authentication/AuthenticationStack.csproj"
cdk deploy ConfigurationStack<POSTFIX> --require-approval=never --app "dotnet run --project cdk/src/StockPriceService/StockPriceService.csproj"
cdk deploy StockPriceStack<POSTFIX> --require-approval=never --app "dotnet run --project cdk/src/StockPriceService/StockPriceService.csproj"
cdk deploy NotificationServiceStack<POSTFIX> --require-approval=never --app "dotnet run --project cdk/src/NotificationService/NotificationService.csproj"
If you to want to run the functional tests, you will also need to deploy the asynchronous test infrastructure:
cdk deploy StockTestInfrastructure<POSTFIX> --require-approval=never --app "dotnet run --project cdk/src/StockPriceService/StockPriceService.csproj"
The deployed API Gateway includes authentication using Amazon Cognito. Once deployed, you will need to run the below commands to create and configure a valid user within the Cognito user pool. Alternatively, you can run the application under ./utilities/ConfigureUserPoolUtility
to walk through the setup of a user you can use to access the API.
cd ./utilities/ConfigureUserPoolUtility
dotnet run
aws cognito-idp admin-create-user --user-pool-id <USER_POOL_ID> --username john@example.com --user-attributes Name="given_name",Value="john" Name="family_name",Value="smith"
aws cognito-idp admin-set-user-password --user-pool-id <USER_POOL_ID> --username john@example.com --password "<PASSWORD>" --permanent
aws cognito-idp admin-initiate-auth --cli-input-json file://auth.json
auth.json
{
"UserPoolId": "<USER_POOl_ID>",
"ClientId": "<CLIENT_ID>",
"AuthFlow": "ADMIN_NO_SRP_AUTH",
"AuthParameters": {
"USERNAME": "john@example.com",
"PASSWORD": "<PASSWORD>"
}
}
The project contains examples of multiple types of tests:
- Unit Tests: Mock out all external integrations allowing tests to focus purely on business logic
- Integration Tests: Tests to run locally that interact with actual deployed AWS resources
- Functional Tests: Tests that run against actual AWS resources e.g. make API calls to API Gateway
The integration tests also support using the same STACK_POSTFIX
environment variable. If you set the variable, deploy the CDK stack and then run the integration tests using the same terminal window your test execution will use the postfixed resources.
When running the functional tests locally, you also need to set the TEMPORARY_PASSWORD
environment variable. This allows the functional tests to create a temporary user in Cognito for the tests to use.
For more information on testing, check out this YouTube Video on testing and debugging your Lambda functions locally.
AWS Lambda PowerTuning is used as a data driven way to set the memory allocation. For example, below is an output from Lambda PowerTuning for the .NET 8 AOT compile ASP.NET example.
- [] Add examples of different Lambda event sources
- [] SQS
- [] DynamoDB Stream
- [] SNS
- [] EventBridge
- [] S3
- [] Kinesis
Code contributions are welcomed. Read this guide.
Read our code of conduct here.
- Blog Website James Eastham
- LinkedIn: james-eastham
- Twitter: @plantpowerjames
This library is licensed under the MIT License. See the LICENSE file.