From 3d33bd28e5b0159379476f082a69b0bb01bf3b71 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 16 Dec 2025 19:19:05 +0000 Subject: [PATCH 1/6] feat: add templates for dotnet10 runtime --- .github/workflows/build_test_invoke.yml | 20 +- dotnet10/cw-event/.gitignore | 168 ++++++++ dotnet10/cw-event/README.md | 15 + dotnet10/cw-event/cookiecutter.json | 13 + dotnet10/cw-event/setup.cfg | 2 + .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 145 +++++++ .../events/event-cloudwatch-event.json | 12 + .../omnisharp.json | 8 + .../CloudWatchEventSource.csproj | 18 + .../src/CloudWatchEventSource/Function.cs | 27 ++ .../src/CloudWatchEventSource/Readme.md | 49 +++ .../aws-lambda-tools-defaults.json | 15 + .../template.yaml | 41 ++ .../CloudWatchEventSource.Tests.csproj | 18 + .../FunctionTest.cs | 33 ++ dotnet10/hello-img/.gitignore | 168 ++++++++ dotnet10/hello-img/Pipfile | 13 + dotnet10/hello-img/README.md | 42 ++ dotnet10/hello-img/cookiecutter.json | 8 + dotnet10/hello-img/setup.cfg | 2 + dotnet10/hello-img/tests/test_cookiecutter.py | 34 ++ .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 127 ++++++ .../events/event.json | 63 +++ .../omnisharp.json | 8 + .../src/HelloWorld/Dockerfile | 23 + .../src/HelloWorld/Function.cs | 47 ++ .../src/HelloWorld/HelloWorld.csproj | 18 + .../HelloWorld/aws-lambda-tools-defaults.json | 12 + .../template.yaml | 42 ++ .../test/HelloWorld.Test/FunctionTest.cs | 57 +++ .../HelloWorld.Test/HelloWorld.Tests.csproj | 20 + dotnet10/hello-native-aot/.gitignore | 168 ++++++++ dotnet10/hello-native-aot/Pipfile | 13 + dotnet10/hello-native-aot/README.md | 39 ++ dotnet10/hello-native-aot/cookiecutter.json | 13 + dotnet10/hello-native-aot/setup.cfg | 2 + .../tests/test_cookiecutter.py | 47 ++ .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 125 ++++++ .../events/event.json | 63 +++ .../omnisharp.json | 8 + .../src/HelloWorldAot/Function.cs | 69 +++ .../src/HelloWorldAot/HelloWorldAot.csproj | 23 + .../aws-lambda-tools-defaults.json | 12 + .../template.yaml | 48 +++ .../test/HelloWorldAot.Test/FunctionTest.cs | 56 +++ .../HelloWorldAot.Tests.csproj | 21 + dotnet10/hello-pt/.gitignore | 168 ++++++++ dotnet10/hello-pt/Pipfile | 13 + dotnet10/hello-pt/README.md | 37 ++ dotnet10/hello-pt/cookiecutter.json | 13 + dotnet10/hello-pt/setup.cfg | 2 + dotnet10/hello-pt/tests/test_cookiecutter.py | 47 ++ .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 166 +++++++ .../events/event.json | 63 +++ .../omnisharp.json | 8 + .../src/HelloWorld/Function.cs | 97 +++++ .../src/HelloWorld/HelloWorld.csproj | 27 ++ .../HelloWorld/aws-lambda-tools-defaults.json | 12 + .../template.yaml | 73 ++++ .../test/HelloWorld.Test/FunctionTest.cs | 57 +++ .../HelloWorld.Test/HelloWorld.Tests.csproj | 20 + dotnet10/hello/.gitignore | 168 ++++++++ dotnet10/hello/Pipfile | 13 + dotnet10/hello/README.md | 39 ++ dotnet10/hello/cookiecutter.json | 13 + dotnet10/hello/setup.cfg | 2 + dotnet10/hello/tests/test_cookiecutter.py | 47 ++ .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 125 ++++++ .../events/event.json | 63 +++ .../omnisharp.json | 8 + .../src/HelloWorld/Function.cs | 47 ++ .../src/HelloWorld/HelloWorld.csproj | 18 + .../HelloWorld/aws-lambda-tools-defaults.json | 12 + .../template.yaml | 48 +++ .../test/HelloWorld.Test/FunctionTest.cs | 57 +++ .../HelloWorld.Test/HelloWorld.Tests.csproj | 20 + dotnet10/s3/.gitignore | 168 ++++++++ dotnet10/s3/Pipfile | 13 + dotnet10/s3/README.md | 19 + dotnet10/s3/cookiecutter.json | 13 + dotnet10/s3/setup.cfg | 2 + .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 153 +++++++ .../events/event.json | 38 ++ .../omnisharp.json | 8 + .../src/S3EventSource/Function.cs | 70 +++ .../src/S3EventSource/S3EventSource.csproj | 19 + .../template.yaml | 53 +++ .../test/S3EventSource.Tests/FunctionTest.cs | 75 ++++ .../S3EventSource.Tests/S3Event.Tests.csproj | 18 + dotnet10/scratch/.gitignore | 168 ++++++++ dotnet10/scratch/Pipfile | 13 + dotnet10/scratch/README.md | 15 + dotnet10/scratch/cookiecutter.json | 13 + dotnet10/scratch/setup.cfg | 2 + .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 141 ++++++ .../omnisharp.json | 8 + .../src/ScratchLambda/Function.cs | 30 ++ .../src/ScratchLambda/ScratchLambda.csproj | 17 + .../template.yaml | 40 ++ .../test/ScratchLambda.Tests/FunctionTest.cs | 27 ++ .../ScratchLambda.Tests.csproj | 15 + dotnet10/sns/.gitignore | 170 ++++++++ dotnet10/sns/Pipfile | 13 + dotnet10/sns/README.md | 15 + dotnet10/sns/cookiecutter.json | 13 + dotnet10/sns/setup.cfg | 2 + .../src/SNSEventSource/Function.cs | 45 ++ .../src/SNSEventSource/Readme.md | 51 +++ .../src/SNSEventSource/SNSEventSource.csproj | 18 + .../aws-lambda-tools-defaults.json | 15 + .../template.yaml | 58 +++ .../test/SNSEventSource.Tests/FunctionTest.cs | 37 ++ .../SNSEventSource.Tests.csproj | 18 + dotnet10/sqs/.gitignore | 168 ++++++++ dotnet10/sqs/Pipfile | 13 + dotnet10/sqs/README.md | 17 + dotnet10/sqs/cookiecutter.json | 13 + dotnet10/sqs/setup.cfg | 2 + .../{{cookiecutter.project_name}}/.gitignore | 406 ++++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 141 ++++++ .../events/event-sqs.json | 20 + .../omnisharp.json | 8 + .../src/SQSEventSource/Function.cs | 49 +++ .../src/SQSEventSource/SQSEventSource.csproj | 18 + .../template.yaml | 56 +++ .../test/SQSEventSource.Tests/FunctionTest.cs | 36 ++ .../SQSEventSource.Tests.csproj | 18 + dotnet10/step-func/.gitignore | 168 ++++++++ dotnet10/step-func/Pipfile | 13 + dotnet10/step-func/README.md | 17 + dotnet10/step-func/cookiecutter.json | 13 + dotnet10/step-func/setup.cfg | 2 + dotnet10/step-func/tests/test_cookiecutter.py | 54 +++ .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 104 +++++ .../functions/StockBuyer/Function.cs | 57 +++ .../functions/StockBuyer/StockBuyer.csproj | 19 + .../StockBuyer/aws-lambda-tools-defaults.json | 12 + .../functions/StockChecker/Function.cs | 41 ++ .../StockChecker/StockChecker.csproj | 19 + .../aws-lambda-tools-defaults.json | 12 + .../functions/StockSeller/Function.cs | 57 +++ .../functions/StockSeller/StockSeller.csproj | 19 + .../aws-lambda-tools-defaults.json | 12 + .../omnisharp.json | 8 + .../statemachine/stockTrader.asl.json | 97 +++++ .../template.yaml | 94 ++++ .../tests/StockBuyer.Test/FunctionTest.cs | 35 ++ .../StockBuyer.Test/StockBuyer.Tests.csproj | 18 + .../tests/StockChecker.Test/FunctionTest.cs | 20 + .../StockChecker.Tests.csproj | 18 + .../tests/StockSeller.Test/FunctionTest.cs | 36 ++ .../StockSeller.Test/StockSeller.Tests.csproj | 18 + dotnet10/web/.gitignore | 168 ++++++++ dotnet10/web/README.md | 42 ++ dotnet10/web/cookiecutter.json | 7 + dotnet10/web/setup.cfg | 2 + .../{{cookiecutter.project_name}}/.gitignore | 405 +++++++++++++++++ .../{{cookiecutter.project_name}}/README.md | 146 +++++++ .../ServerlessAPI.sln | 36 ++ .../omnisharp.json | 8 + .../Controllers/BooksController.cs | 104 +++++ .../src/ServerlessAPI/Entities/Book.cs | 30 ++ .../src/ServerlessAPI/Program.cs | 42 ++ .../src/ServerlessAPI/Readme.md | 50 +++ .../Repositories/BookRepository.cs | 126 ++++++ .../Repositories/IBookRepository.cs | 44 ++ .../src/ServerlessAPI/ServerlessAPI.csproj | 24 ++ .../appsettings.Development.json | 8 + .../src/ServerlessAPI/appsettings.json | 9 + .../aws-lambda-tools-defaults.json | 14 + .../template.yaml | 56 +++ .../ServerlessAPI.Tests/BookControllerTest.cs | 52 +++ .../ServerlessAPI.Tests/MockBookRepository.cs | 52 +++ .../ServerlessAPI.Tests.csproj | 29 ++ manifest-v2.json | 92 ++++ .../dotnet/test_build_invoke_dotnet10.py | 93 ++++ .../unit_test/test_unit_test_dotnet10.py | 67 +++ 185 files changed, 11918 insertions(+), 7 deletions(-) create mode 100644 dotnet10/cw-event/.gitignore create mode 100644 dotnet10/cw-event/README.md create mode 100644 dotnet10/cw-event/cookiecutter.json create mode 100644 dotnet10/cw-event/setup.cfg create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/events/event-cloudwatch-event.json create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/CloudWatchEventSource.csproj create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Function.cs create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Readme.md create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/aws-lambda-tools-defaults.json create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/CloudWatchEventSource.Tests.csproj create mode 100644 dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/FunctionTest.cs create mode 100644 dotnet10/hello-img/.gitignore create mode 100644 dotnet10/hello-img/Pipfile create mode 100644 dotnet10/hello-img/README.md create mode 100644 dotnet10/hello-img/cookiecutter.json create mode 100644 dotnet10/hello-img/setup.cfg create mode 100644 dotnet10/hello-img/tests/test_cookiecutter.py create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/events/event.json create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs create mode 100644 dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj create mode 100644 dotnet10/hello-native-aot/.gitignore create mode 100644 dotnet10/hello-native-aot/Pipfile create mode 100644 dotnet10/hello-native-aot/README.md create mode 100644 dotnet10/hello-native-aot/cookiecutter.json create mode 100644 dotnet10/hello-native-aot/setup.cfg create mode 100644 dotnet10/hello-native-aot/tests/test_cookiecutter.py create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/events/event.json create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/Function.cs create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/HelloWorldAot.csproj create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/aws-lambda-tools-defaults.json create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/FunctionTest.cs create mode 100644 dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/HelloWorldAot.Tests.csproj create mode 100644 dotnet10/hello-pt/.gitignore create mode 100644 dotnet10/hello-pt/Pipfile create mode 100644 dotnet10/hello-pt/README.md create mode 100644 dotnet10/hello-pt/cookiecutter.json create mode 100644 dotnet10/hello-pt/setup.cfg create mode 100644 dotnet10/hello-pt/tests/test_cookiecutter.py create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/events/event.json create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs create mode 100644 dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj create mode 100644 dotnet10/hello/.gitignore create mode 100644 dotnet10/hello/Pipfile create mode 100644 dotnet10/hello/README.md create mode 100644 dotnet10/hello/cookiecutter.json create mode 100644 dotnet10/hello/setup.cfg create mode 100644 dotnet10/hello/tests/test_cookiecutter.py create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/events/event.json create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs create mode 100644 dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj create mode 100644 dotnet10/s3/.gitignore create mode 100644 dotnet10/s3/Pipfile create mode 100644 dotnet10/s3/README.md create mode 100644 dotnet10/s3/cookiecutter.json create mode 100644 dotnet10/s3/setup.cfg create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/events/event.json create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/Function.cs create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/S3EventSource.csproj create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/FunctionTest.cs create mode 100644 dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/S3Event.Tests.csproj create mode 100644 dotnet10/scratch/.gitignore create mode 100644 dotnet10/scratch/Pipfile create mode 100644 dotnet10/scratch/README.md create mode 100644 dotnet10/scratch/cookiecutter.json create mode 100644 dotnet10/scratch/setup.cfg create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/Function.cs create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/ScratchLambda.csproj create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/FunctionTest.cs create mode 100644 dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/ScratchLambda.Tests.csproj create mode 100644 dotnet10/sns/.gitignore create mode 100644 dotnet10/sns/Pipfile create mode 100644 dotnet10/sns/README.md create mode 100644 dotnet10/sns/cookiecutter.json create mode 100644 dotnet10/sns/setup.cfg create mode 100644 dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Function.cs create mode 100644 dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Readme.md create mode 100644 dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/SNSEventSource.csproj create mode 100644 dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/aws-lambda-tools-defaults.json create mode 100644 dotnet10/sns/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/FunctionTest.cs create mode 100644 dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/SNSEventSource.Tests.csproj create mode 100644 dotnet10/sqs/.gitignore create mode 100644 dotnet10/sqs/Pipfile create mode 100644 dotnet10/sqs/README.md create mode 100644 dotnet10/sqs/cookiecutter.json create mode 100644 dotnet10/sqs/setup.cfg create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/events/event-sqs.json create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/Function.cs create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/SQSEventSource.csproj create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/FunctionTest.cs create mode 100644 dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/SQSEventSource.Tests.csproj create mode 100644 dotnet10/step-func/.gitignore create mode 100644 dotnet10/step-func/Pipfile create mode 100644 dotnet10/step-func/README.md create mode 100644 dotnet10/step-func/cookiecutter.json create mode 100644 dotnet10/step-func/setup.cfg create mode 100644 dotnet10/step-func/tests/test_cookiecutter.py create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/Function.cs create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/StockBuyer.csproj create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/aws-lambda-tools-defaults.json create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/Function.cs create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/StockChecker.csproj create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/aws-lambda-tools-defaults.json create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/Function.cs create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/StockSeller.csproj create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/aws-lambda-tools-defaults.json create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/statemachine/stockTrader.asl.json create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/FunctionTest.cs create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/StockBuyer.Tests.csproj create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/FunctionTest.cs create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/StockChecker.Tests.csproj create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/FunctionTest.cs create mode 100644 dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/StockSeller.Tests.csproj create mode 100644 dotnet10/web/.gitignore create mode 100644 dotnet10/web/README.md create mode 100644 dotnet10/web/cookiecutter.json create mode 100644 dotnet10/web/setup.cfg create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/.gitignore create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/README.md create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/ServerlessAPI.sln create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/omnisharp.json create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Controllers/BooksController.cs create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Entities/Book.cs create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Program.cs create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Readme.md create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/BookRepository.cs create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/IBookRepository.cs create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/ServerlessAPI.csproj create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.Development.json create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.json create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/aws-lambda-tools-defaults.json create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/template.yaml create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/BookControllerTest.cs create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/MockBookRepository.cs create mode 100644 dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/ServerlessAPI.Tests.csproj create mode 100644 tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py create mode 100644 tests/integration/unit_test/test_unit_test_dotnet10.py diff --git a/.github/workflows/build_test_invoke.yml b/.github/workflows/build_test_invoke.yml index 964b3b44c..4c6959de3 100644 --- a/.github/workflows/build_test_invoke.yml +++ b/.github/workflows/build_test_invoke.yml @@ -102,12 +102,12 @@ jobs: - version: '3.13' type: 'Invoke' file: 'tests/integration/build_invoke/python/test_python_3_13.py' - - version: '3.14' - type: 'Test' - file: 'tests/integration/unit_test/test_unit_test_python3_14.py' - - version: '3.14' - type: 'Invoke' - file: 'tests/integration/build_invoke/python/test_python_3_14.py' + # - version: '3.14' + # type: 'Test' + # file: 'tests/integration/unit_test/test_unit_test_python3_14.py' + # - version: '3.14' + # type: 'Invoke' + # file: 'tests/integration/build_invoke/python/test_python_3_14.py' env: PYTHON_VERSION_INSTALL: ${{ matrix.version }} runs-on: ubuntu-latest @@ -369,12 +369,18 @@ jobs: - version: '8' type: 'Invoke' file: 'tests/integration/build_invoke/dotnet/test_build_invoke_dotnet8.py' + - version: '10' + type: 'Test' + file: 'tests/integration/unit_test/test_unit_test_dotnet10.py' + # - version: '10' + # type: 'Invoke' + # file: 'tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py' steps: - uses: actions/checkout@v3 name: Checkout PR - uses: ./.github/actions/aws-sam-cli-develop name: Install develop version of AWS SAM CLI - - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@v5 name: Setup dotnet ${{ matrix.version }} with: dotnet-version: ${{ matrix.version }} diff --git a/dotnet10/cw-event/.gitignore b/dotnet10/cw-event/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/cw-event/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/cw-event/README.md b/dotnet10/cw-event/README.md new file mode 100644 index 000000000..3f40f7bd6 --- /dev/null +++ b/dotnet10/cw-event/README.md @@ -0,0 +1,15 @@ +# Cookiecutter .NET 8 CloudWatch Events Quick Start Application + +A cookiecutter template to create a .NET Core CloudWatch Events Quick Start Application using [Serverless Application Model (SAM)](https://github.com/awslabs/serverless-application-model). + +## Requirements + +* [AWS SAM CLI](https://github.com/awslabs/aws-sam-cli) + +## Usage + +Access this template by running `sam init` and choosing it from the list of available templates. + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) \ No newline at end of file diff --git a/dotnet10/cw-event/cookiecutter.json b/dotnet10/cw-event/cookiecutter.json new file mode 100644 index 000000000..590d62b57 --- /dev/null +++ b/dotnet10/cw-event/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} diff --git a/dotnet10/cw-event/setup.cfg b/dotnet10/cw-event/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/cw-event/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/.gitignore b/dotnet10/cw-event/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/README.md b/dotnet10/cw-event/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..5970788e9 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,145 @@ +# {{cookiecutter.project_name}} + +This project contains source code and supporting files for a serverless application that you can deploy with the AWS Serverless Application Model (AWS SAM) command line interface (CLI). It includes the following files and folders: + +- `src` - Code for the application's Lambda function. +- `events` - Invocation events that you can use to invoke the function. +- `test` - Unit tests for the application code. +- `template.yaml` - A template that defines the application's AWS resources. + +Resources for this project are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open-source plugin for popular IDEs that uses the AWS SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds step-through debugging for Lambda function code. + +To get started, see the following: + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The AWS SAM CLI is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the AWS SAM CLI, you need the following tools: + +* AWS SAM CLI - [Install the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community). + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +## Use the AWS SAM CLI to build and test locally + +Build your application by using the `sam build` command. + +```bash +{{cookiecutter.project_name}}$ sam build +``` + +The AWS SAM CLI installs dependencies that are defined in `package.json`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{cookiecutter.project_name}}$ sam local invoke ScheduledEventLogger --event events/event-cloudwatch-event.json +``` + +## Add a resource to your application + +The application template uses AWS SAM to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources, such as functions, triggers, and APIs. For resources that aren't included in the [AWS SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use the standard [AWS CloudFormation resource types](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html). + +Update `template.yaml` to add a dead-letter queue to your application. In the **Resources** section, add a resource named **MyQueue** with the type **AWS::SQS::Queue**. Then add a property to the **AWS::Serverless::Function** resource named **DeadLetterQueue** that targets the queue's Amazon Resource Name (ARN), and a policy that grants the function permission to access the queue. + +```yaml +Resources: + ScheduledEventLogger: + Type: AWS::Serverless::Function + Properties: + FunctionName: ScheduledEventLoggerFunction + Description: A Lambda function that logs the payload of messages from a scheduled CloudWatch Event + CodeUri: ./src/lambdaEvent/ + Handler: lambdaEvent::lambdaEvent.Function::FunctionHandler + Runtime: dotnet10 + MemorySize: 512 + Timeout: 100 + # This property associates this Lambda function with a scheduled CloudWatch Event. For all available properties, see + # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#schedule + # This example runs every hour. + Events: + CloudWatchEvent: + Type: Schedule + Properties: + Schedule: cron(0 * * * ? *) +``` + +The dead-letter queue is a location for Lambda to send events that could not be processed. It's only used if you invoke your function asynchronously, but it's useful here to show how you can modify your application's resources and function configuration. + +Deploy the updated application. + +```bash +{{cookiecutter.project_name}}$ sam deploy +``` + +Open the [**Applications**](https://console.aws.amazon.com/lambda/home#/applications) page of the Lambda console, and choose your application. When the deployment completes, view the application resources on the **Overview** tab to see the new resource. Then, choose the function to see the updated configuration that specifies the dead-letter queue. + + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, the AWS SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs that are generated by your Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +**NOTE:** This command works for all Lambda functions, not just the ones you deploy using AWS SAM. + +```bash +{{cookiecutter.project_name}}$ sam logs -n ScheduledEventLogger --stack-name sam-app --tail +``` + +**NOTE:** This uses the logical name of the function within the stack. This is the correct name to use when searching logs inside an AWS Lambda function within a CloudFormation stack, even if the deployed function name varies due to CloudFormation's unique resource name generation. + +You can find more information and examples about filtering Lambda function logs in the [AWS SAM CLI documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests for the Lambda functions are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/{{ cookiecutter.project_name }}.Tests/{{ cookiecutter.project_name }}.Tests.csproj +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +For an introduction to the AWS SAM specification, the AWS SAM CLI, and serverless application concepts, see the [AWS SAM Developer Guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html). + +Next, you can use the AWS Serverless Application Repository to deploy ready-to-use apps that go beyond Hello World samples and learn how authors developed their applications. For more information, see the [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) and the [AWS Serverless Application Repository Developer Guide](https://docs.aws.amazon.com/serverlessrepo/latest/devguide/what-is-serverlessrepo.html). diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/events/event-cloudwatch-event.json b/dotnet10/cw-event/{{cookiecutter.project_name}}/events/event-cloudwatch-event.json new file mode 100644 index 000000000..6c3cb7e3c --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/events/event-cloudwatch-event.json @@ -0,0 +1,12 @@ +{ + "id": "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c", + "detail-type": "Scheduled Event", + "source": "aws.events", + "account": "", + "time": "1970-01-01T00:00:00Z", + "region": "us-west-2", + "resources": [ + "arn:aws:events:us-west-2:123456789012:rule/ExampleRule" + ], + "detail": {} +} diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/cw-event/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/CloudWatchEventSource.csproj b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/CloudWatchEventSource.csproj new file mode 100644 index 000000000..2b3f3d841 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/CloudWatchEventSource.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + \ No newline at end of file diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Function.cs b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Function.cs new file mode 100644 index 000000000..a16302fd6 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Function.cs @@ -0,0 +1,27 @@ +using System.Text.Json; + +using Amazon.Lambda.Core; +using Amazon.Lambda.CloudWatchEvents; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace CloudWatchEventSource; + +public class Function +{ + + /// + /// A simple function that takes a string and does a ToUpper + /// + /// + /// + /// + public string FunctionHandler(CloudWatchEvent evnt, ILambdaContext context) + { + // All log statements are written to CloudWatch by default. For more information, see + // https://docs.aws.amazon.com/lambda/latest/dg/csharp-logging.html + context.Logger.LogLine(JsonSerializer.Serialize(evnt)); + return "Done"; + } +} diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Readme.md b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Readme.md new file mode 100644 index 000000000..905664f92 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/Readme.md @@ -0,0 +1,49 @@ +# AWS Lambda Empty Function Project + +This starter project consists of: +* Function.cs - class file containing a class with a single function handler method +* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS + +You may also have a test project depending on the options selected. + +The generated function handler is a simple method accepting a string argument that returns the uppercase equivalent of the input string. Replace the body of this method, and parameters, to suit your needs. + +## Here are some steps to follow from Visual Studio: + +To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. + +To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. + +To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. + +To configure event sources for your deployed function, for example to have your function invoked when an object is created in an Amazon S3 bucket, use the Event Sources tab in the opened Function View window. + +To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. + +To view execution logs of invocations of your function use the Logs tab in the opened Function View window. + +## Here are some steps to follow to get started from the command line: + +Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. + +Install Amazon.Lambda.Tools Global Tools if not already installed. +``` + dotnet tool install -g Amazon.Lambda.Tools +``` + +If already installed check if new version is available. +``` + dotnet tool update -g Amazon.Lambda.Tools +``` + +Execute unit tests +``` + cd "{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests" + dotnet test +``` + +Deploy function to AWS Lambda +``` + cd "{{cookiecutter.project_name}}" + sam deploy +``` diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/aws-lambda-tools-defaults.json b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..565e8f831 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/src/CloudWatchEventSource/aws-lambda-tools-defaults.json @@ -0,0 +1,15 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "function-runtime": "dotnet10", + "function-memory-size": 512, + "function-timeout": 30, + "function-handler": "CloudWatchEventSource::CloudWatchEventSource.Function::FunctionHandler" +} \ No newline at end of file diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/template.yaml b/dotnet10/cw-event/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..f684f4c12 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,41 @@ +# This is the SAM template that represents the architecture of your serverless application +# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template-basics.html + +# The AWSTemplateFormatVersion identifies the capabilities of the template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html +AWSTemplateFormatVersion: 2010-09-09 +Description: >- + Schedule CloudWatch Event that triggers Lambda function every hour + +# Transform section specifies one or more macros that AWS CloudFormation uses to process your template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html +Transform: AWS::Serverless-2016-10-31 + +# Resources declares the AWS resources that you want to include in the stack +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html +Resources: + # This is the Lambda function definition associated with the source code: sqs-payload-logger.js. For all available properties, see + # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + ScheduledEventLogger: + Type: AWS::Serverless::Function + Properties: + Description: A Lambda function that logs the payload of messages from a scheduled CloudWatch Event + CodeUri: ./src/CloudWatchEventSource/ + Handler: CloudWatchEventSource::CloudWatchEventSource.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + MemorySize: 512 + Timeout: 100 + # This property associates this Lambda function with a scheduled CloudWatch Event. For all available properties, see + # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#schedule + # This example runs every hour. + Events: + CloudWatchEvent: + Type: Schedule + Properties: + Schedule: cron(0 * * * ? *) diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/CloudWatchEventSource.Tests.csproj b/dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/CloudWatchEventSource.Tests.csproj new file mode 100644 index 000000000..7a513bd52 --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/CloudWatchEventSource.Tests.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + + + + + + + + + + + + + \ No newline at end of file diff --git a/dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/FunctionTest.cs b/dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/FunctionTest.cs new file mode 100644 index 000000000..a6652179c --- /dev/null +++ b/dotnet10/cw-event/{{cookiecutter.project_name}}/test/CloudWatchEventSource.Tests/FunctionTest.cs @@ -0,0 +1,33 @@ +using Xunit; +using Amazon.Lambda.Core; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.CloudWatchEvents; + +namespace CloudWatchEventSource.Tests; + +public class FunctionTest +{ + [Fact] + public void TestToUpperFunction() + { + + // Invoke the lambda function and confirm the string was upper cased. + var function = new Function(); + var context = new TestLambdaContext(); + var eventPayload = new CloudWatchEvent() + { + Id = "cdc73f9d-aea9-11e3-9d5a-835b769c0d9c", + DetailType = "Scheduled Event", + Source = "aws.events", + Account = "", + Time = Convert.ToDateTime("1970-01-01T00:00:00Z"), + Region = "us-west-2", + Resources = new List() { "arn:aws:events:us-west-2:123456789012:rule/ExampleRule" }, + Detail = new { } + }; + + var functionResult = function.FunctionHandler(eventPayload, context); + + Assert.Equal("Done", functionResult); + } +} diff --git a/dotnet10/hello-img/.gitignore b/dotnet10/hello-img/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/hello-img/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/hello-img/Pipfile b/dotnet10/hello-img/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/hello-img/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/hello-img/README.md b/dotnet10/hello-img/README.md new file mode 100644 index 000000000..0c4d582f7 --- /dev/null +++ b/dotnet10/hello-img/README.md @@ -0,0 +1,42 @@ +# Cookiecutter SAM for dotNet based Lambda functions + +This is a [Cookiecutter](https://github.com/audreyr/cookiecutter) template to create a Serverless Hello World App based on Serverless Application Model (SAM) and dotnet 10.0. + +It is important to note that you should not try to `git clone` this project but use `cookiecutter` CLI instead as ``{{cookiecutter.project_name}}`` will be rendered based on your input and therefore all variables and files will be rendered properly. + +## Requirements + +Install `cookiecutter` command line: + +**Pip users**: + +* `pip install cookiecutter` + +**Homebrew users**: + +* `brew install cookiecutter` + +**Windows or Pipenv users**: + +* `pipenv install cookiecutter` + +**NOTE**: [`Pipenv`](https://github.com/pypa/pipenv) is the new and recommended Python packaging tool that works across multiple platforms and makes Windows a first-class citizen. + +## Usage + +Generate a new SAM based Serverless App: `cookiecutter gh:aws-samples/cookiecutter-aws-sam-hello-dotnet`. + +You'll be prompted a few questions to help this cookiecutter template to scaffold this project and after its completed you should see a new folder at your current path with the name of the project you gave as input. + +**NOTE**: After you understand how cookiecutter works (cookiecutter.json, mainly), you can fork this repo and apply your own mechanisms to accelerate your development process and this can be followed for any programming language and OS. + + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) + + +License +------- + +This project is licensed under the terms of the [MIT License with no attribution](/LICENSE) diff --git a/dotnet10/hello-img/cookiecutter.json b/dotnet10/hello-img/cookiecutter.json new file mode 100644 index 000000000..3b12b41da --- /dev/null +++ b/dotnet10/hello-img/cookiecutter.json @@ -0,0 +1,8 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10.0", + "_copy_without_render": [ + ".gitignore" + ] + +} \ No newline at end of file diff --git a/dotnet10/hello-img/setup.cfg b/dotnet10/hello-img/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/hello-img/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/hello-img/tests/test_cookiecutter.py b/dotnet10/hello-img/tests/test_cookiecutter.py new file mode 100644 index 000000000..9af69efbf --- /dev/null +++ b/dotnet10/hello-img/tests/test_cookiecutter.py @@ -0,0 +1,34 @@ +""" + Tests cookiecutter baking process and rendered content +""" + + +def test_project_tree(cookies): + result = cookies.bake(extra_context={"project_name": "hello sam"}) + assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == "hello sam" + assert result.project.isdir() + assert result.project.join(".gitignore").isfile() + assert result.project.join("template.yaml").isfile() + assert result.project.join("README.md").isfile() + assert result.project.join("src").isdir() + assert result.project.join("test").isdir() + assert result.project.join("src", "HelloWorld").isdir() + assert result.project.join("src", "HelloWorld", "HelloWorld.csproj").isfile() + assert result.project.join("src", "HelloWorld", "Function.cs").isfile() + assert result.project.join("src", "HelloWorld", "aws-lambda-tools-defaults.json").isfile() + assert result.project.join("test", "HelloWorld.Test", "FunctionTest.cs").isfile() + assert result.project.join("test", "HelloWorld.Test", "HelloWorld.Tests.csproj").isfile() + + +def test_app_content(cookies): + result = cookies.bake(extra_context={"project_name": "my_lambda"}) + app_file = result.project.join("src", "HelloWorld", "Function.cs") + app_content = app_file.readlines() + app_content = "".join(app_content) + + contents = ("GetCallingIP", "GetStringAsync", "location", "message", "hello world", "StatusCode") + + for content in contents: + assert content in app_content diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/.gitignore b/dotnet10/hello-img/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/README.md b/dotnet10/hello-img/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..5b974d284 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,127 @@ +# {{ cookiecutter.project_name }} + +This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. + +- src - Code for the application's Lambda function and Project Dockerfile. +- events - Invocation events that you can use to invoke the function. +- test - Unit tests for the application code. +- template.yaml - A template that defines the application's AWS resources. + +The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started. + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the SAM CLI, you need the following tools. + +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) + +You may need the following for local testing. +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download) + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build a docker image from a Dockerfile and then copy the source of your application inside the Docker image. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +You can find your API Gateway Endpoint URL in the output values displayed after deployment. + +## Use the SAM CLI to build and test locally + +Build your application with the `sam build` command. + +```bash +{{ cookiecutter.project_name }}$ sam build +``` + +The SAM CLI builds a docker image from a Dockerfile and then installs dependencies defined in `src/HelloWorld.csproj` inside the docker image. The processed template file is saved in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{ cookiecutter.project_name }}$ sam local invoke HelloWorldFunction --event events/event.json +``` + +The SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000. + +```bash +{{ cookiecutter.project_name }}$ sam local start-api +{{ cookiecutter.project_name }}$ curl http://localhost:3000/ +``` + +The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path. + +```yaml + Events: + HelloWorld: + Type: Api + Properties: + Path: /hello + Method: get +``` + +## Add a resource to your application +The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. + +```bash +{{ cookiecutter.project_name }}$ sam logs -n HelloWorldFunction --stack-name {{ cookiecutter.project_name }} --tail +``` + +You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/HelloWorld.Test +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. + +Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/events/event.json b/dotnet10/hello-img/{{cookiecutter.project_name}}/events/event.json new file mode 100644 index 000000000..3822fadaa --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/events/event.json @@ -0,0 +1,63 @@ +{ + "body": "{\"message\": \"hello world\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } + } + \ No newline at end of file diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/hello-img/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile new file mode 100644 index 000000000..b34d90f37 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile @@ -0,0 +1,23 @@ +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-image + +ARG FUNCTION_DIR="/build" +ARG SAM_BUILD_MODE="run" +ENV PATH="/root/.dotnet/tools:${PATH}" + +RUN apt-get update && apt-get -y install zip + +RUN mkdir $FUNCTION_DIR +WORKDIR $FUNCTION_DIR +COPY Function.cs HelloWorld.csproj aws-lambda-tools-defaults.json $FUNCTION_DIR/ +RUN dotnet tool install -g Amazon.Lambda.Tools + +# Build and Copy artifacts depending on build mode. +RUN mkdir -p build_artifacts +RUN if [ "$SAM_BUILD_MODE" = "debug" ]; then dotnet lambda package --configuration Debug; else dotnet lambda package --configuration Release; fi +RUN if [ "$SAM_BUILD_MODE" = "debug" ]; then cp -r /build/bin/Debug/net10.0/publish/* /build/build_artifacts; else cp -r /build/bin/Release/net10.0/publish/* /build/build_artifacts; fi + +FROM public.ecr.aws/lambda/dotnet:8 + +COPY --from=build-image /build/build_artifacts/ /var/task/ +# Command can be overwritten by providing a different command in the template directly. +CMD ["HelloWorld::HelloWorld.Function::FunctionHandler"] diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs new file mode 100644 index 000000000..49e0d1264 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; + +using Amazon.Lambda.Core; +using Amazon.Lambda.APIGatewayEvents; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace HelloWorld; + +public class Function +{ + + private static readonly HttpClient client = new HttpClient(); + + private static async Task GetCallingIP() + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var msg = await client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + return msg.Replace("\n",""); + } + + public async Task FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) + { + + var location = await GetCallingIP(); + var body = new Dictionary + { + { "message", "hello world" }, + { "location", location } + }; + + return new APIGatewayProxyResponse + { + Body = JsonSerializer.Serialize(body), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + } +} \ No newline at end of file diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj new file mode 100644 index 000000000..c566b8717 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..ef79abab6 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json @@ -0,0 +1,12 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "template": "template.yaml" +} \ No newline at end of file diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/template.yaml b/dotnet10/hello-img/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..ac05716a6 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,42 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Sample SAM Template for {{ cookiecutter.project_name }} + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 10 + MemorySize: 512 + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + PackageType: Image + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + Metadata: + DockerTag: {{cookiecutter.runtime}}-v1 + DockerContext: ./src/HelloWorld + Dockerfile: Dockerfile + DockerBuildArgs: + SAM_BUILD_MODE: run + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs b/dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs new file mode 100644 index 000000000..e36d3c66f --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; +using Xunit; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.APIGatewayEvents; + +namespace HelloWorld.Tests; + +public class FunctionTest +{ + private static readonly HttpClient client = new HttpClient(); + + private static async Task GetCallingIP() + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var stringTask = client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + var msg = await stringTask; + return msg.Replace("\n",""); + } + + [Fact] + public async Task TestHelloWorldFunctionHandler() + { + var request = new APIGatewayProxyRequest(); + var context = new TestLambdaContext(); + string location = GetCallingIP().Result; + Dictionary body = new Dictionary + { + { "message", "hello world" }, + { "location", location }, + }; + + var expectedResponse = new APIGatewayProxyResponse + { + Body = JsonSerializer.Serialize(body), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + + var function = new Function(); + var response = await function.FunctionHandler(request, context); + + Console.WriteLine("Lambda Response: \n" + response.Body); + Console.WriteLine("Expected Response: \n" + expectedResponse.Body); + + Assert.Equal(expectedResponse.Body, response.Body); + Assert.Equal(expectedResponse.Headers, response.Headers); + Assert.Equal(expectedResponse.StatusCode, response.StatusCode); + } +} \ No newline at end of file diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj b/dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj new file mode 100644 index 000000000..c95377008 --- /dev/null +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + + + + + + + + + + + + + + + + diff --git a/dotnet10/hello-native-aot/.gitignore b/dotnet10/hello-native-aot/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/hello-native-aot/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/hello-native-aot/Pipfile b/dotnet10/hello-native-aot/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/hello-native-aot/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/hello-native-aot/README.md b/dotnet10/hello-native-aot/README.md new file mode 100644 index 000000000..6fb16fa5b --- /dev/null +++ b/dotnet10/hello-native-aot/README.md @@ -0,0 +1,39 @@ +# AWS SAM cookiecutter for .NET 8 Lambda functions + +This [cookiecutter](https://github.com/audreyr/cookiecutter) creates a "Hello World" application using the AWS Serverless Application Model (AWS SAM) with the `dotnet10` runtime. For more information on how to use this template, please see the generated project README file. + +**Please note, you should not try to `git clone` this project.** Instead, use `cookiecutter` CLI instead as ``{{cookiecutter.project_name}}`` will be rendered based on your input and therefore all variables and files will be rendered properly. + +## Cookiecutter requirements + +Install `cookiecutter` command line: + +**Pip users**: + +* `pip install cookiecutter` + +**Homebrew users**: + +* `brew install cookiecutter` + +**Windows or Pipenv users**: + +* `pipenv install cookiecutter` + +**NOTE**: [`Pipenv`](https://github.com/pypa/pipenv) is the new and recommended Python packaging tool that works across multiple platforms and makes Windows a first-class citizen. + +### Usage + +Generate a new SAM based Serverless App: `sam init --runtime dotnet10`. + +You'll be prompted a few questions to help this cookiecutter template to scaffold this project and after its completed you should see a new folder at your current path with the name of the project you gave as input. + +**NOTE**: After you understand how cookiecutter works (cookiecutter.json, mainly), you can fork this repo and apply your own mechanisms to accelerate your development process and this can be followed for any programming language and OS. + +### Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) + +### License + +This project is licensed under the terms of the [MIT License with no attribution](/LICENSE) \ No newline at end of file diff --git a/dotnet10/hello-native-aot/cookiecutter.json b/dotnet10/hello-native-aot/cookiecutter.json new file mode 100644 index 000000000..590d62b57 --- /dev/null +++ b/dotnet10/hello-native-aot/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} diff --git a/dotnet10/hello-native-aot/setup.cfg b/dotnet10/hello-native-aot/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/hello-native-aot/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/hello-native-aot/tests/test_cookiecutter.py b/dotnet10/hello-native-aot/tests/test_cookiecutter.py new file mode 100644 index 000000000..82f7800b9 --- /dev/null +++ b/dotnet10/hello-native-aot/tests/test_cookiecutter.py @@ -0,0 +1,47 @@ +""" + Tests cookiecutter baking process and rendered content +""" + + +def test_project_tree(cookies): + result = cookies.bake(extra_context={ + 'project_name': 'hello sam' + }) + assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == 'hello sam' + assert result.project.isdir() + assert result.project.join('.gitignore').isfile() + assert result.project.join('template.yaml').isfile() + assert result.project.join('README.md').isfile() + assert result.project.join('src').isdir() + assert result.project.join('test').isdir() + assert result.project.join('src', 'HelloWorldAot').isdir() + assert result.project.join( + 'src', 'HelloWorldAot', 'HelloWorldAot.csproj').isfile() + assert result.project.join('src', 'HelloWorldAot', 'Function.cs').isfile() + assert result.project.join( + 'src', 'HelloWorldAot', 'aws-lambda-tools-defaults.json').isfile() + assert result.project.join( + 'test', 'HelloWorldAot.Test', 'FunctionTest.cs').isfile() + assert result.project.join( + 'test', 'HelloWorldAot.Test', 'HelloWorldAot.Tests.csproj').isfile() + + +def test_app_content(cookies): + result = cookies.bake(extra_context={'project_name': 'my_lambda'}) + app_file = result.project.join('src', 'HelloWorldAot', 'Function.cs') + app_content = app_file.readlines() + app_content = ''.join(app_content) + + contents = ( + "GetCallingIP", + "GetStringAsync", + "location", + "message", + "hello world", + "StatusCode" + ) + + for content in contents: + assert content in app_content diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/.gitignore b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/README.md b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..134d7cfbd --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,125 @@ +# {{ cookiecutter.project_name }} + +This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. + +- src - Code for the application's Lambda function. +- events - Invocation events that you can use to invoke the function. +- test - Unit tests for the application code. +- template.yaml - A template that defines the application's AWS resources. + +The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started. + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the SAM CLI, you need the following tools. + +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +You can find your API Gateway Endpoint URL in the output values displayed after deployment. + +## Use the SAM CLI to build and test locally + +Build your application with the `sam build` command. + +```bash +{{ cookiecutter.project_name }}$ sam build +``` + +The SAM CLI installs dependencies defined in `src/HelloWorldAot.csproj`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{ cookiecutter.project_name }}$ sam local invoke HelloWorldAotFunction --event events/event.json +``` + +The SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000. + +```bash +{{ cookiecutter.project_name }}$ sam local start-api +{{ cookiecutter.project_name }}$ curl http://localhost:3000/ +``` + +The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path. + +```yaml + Events: + HelloWorldAot: + Type: Api + Properties: + Path: /hello + Method: get +``` + +## Add a resource to your application +The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. + +```bash +{{ cookiecutter.project_name }}$ sam logs -n HelloWorldAotFunction --stack-name {{ cookiecutter.project_name }} --tail +``` + +You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/HelloWorldAot.Test +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. + +Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/events/event.json b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/events/event.json new file mode 100644 index 000000000..1bb5c16ac --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/events/event.json @@ -0,0 +1,63 @@ +{ + "body": "{\"message\": \"hello world with AOT\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } + } + \ No newline at end of file diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/Function.cs b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/Function.cs new file mode 100644 index 000000000..1222fcdff --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/Function.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; + +using Amazon.Lambda.Core; +using Amazon.Lambda.RuntimeSupport; +using Amazon.Lambda.APIGatewayEvents; +using Amazon.Lambda.Serialization.SystemTextJson; + +namespace HelloWorldAot; + +public class Function +{ + private static readonly HttpClient client = new HttpClient(); + + /// + /// The main entry point for the Lambda function. The main function is called once during the Lambda init phase. It + /// initializes the .NET Lambda runtime client passing in the function handler to invoke for each Lambda event and + /// the JSON serializer to use for converting Lambda JSON format to the .NET types. + /// + private static async Task Main() + { + Func> handler = FunctionHandler; + await LambdaBootstrapBuilder.Create(handler, new SourceGeneratorLambdaJsonSerializer()) + .Build() + .RunAsync(); + } + + private static async Task GetCallingIP() + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var msg = await client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + return msg.Replace("\n",""); + } + + public static async Task FunctionHandler(APIGatewayHttpApiV2ProxyRequest apigProxyEvent, ILambdaContext context) + { + + var location = await GetCallingIP(); + var body = new Dictionary + { + { "message", "hello world" }, + { "location", location } + }; + + return new APIGatewayHttpApiV2ProxyResponse + { + Body = JsonSerializer.Serialize(body, typeof(Dictionary), LambdaFunctionJsonSerializerContext.Default), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + } +} + +[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyRequest))] +[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyResponse))] +[JsonSerializable(typeof(Dictionary))] +public partial class LambdaFunctionJsonSerializerContext : JsonSerializerContext +{ + // By using this partial class derived from JsonSerializerContext, we can generate reflection free JSON Serializer code at compile time + // which can deserialize our class and properties. However, we must attribute this class to tell it what types to generate serialization code for. + // See https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-source-generation +} \ No newline at end of file diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/HelloWorldAot.csproj b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/HelloWorldAot.csproj new file mode 100644 index 000000000..1d169d7d2 --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/HelloWorldAot.csproj @@ -0,0 +1,23 @@ + + + exe + net10.0 + enable + enable + Lambda + bootstrap + + true + + true + + true + + + + + + + + diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/aws-lambda-tools-defaults.json b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..ef79abab6 --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/src/HelloWorldAot/aws-lambda-tools-defaults.json @@ -0,0 +1,12 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "template": "template.yaml" +} \ No newline at end of file diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/template.yaml b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..194bc9603 --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,48 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Sample SAM Template for {{ cookiecutter.project_name }} + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 10 + MemorySize: 512 + +Resources: + HelloWorldAotFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: ./src/HelloWorldAot/ + Handler: bootstrap + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + MemorySize: 512 + Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object + Variables: + PARAM1: VALUE + Events: + HelloWorldAot: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldAotApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/Prod/hello/" + HelloWorldAotFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldAotFunction.Arn + HelloWorldAotFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldAotFunctionRole.Arn diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/FunctionTest.cs b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/FunctionTest.cs new file mode 100644 index 000000000..2737203c4 --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/FunctionTest.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; +using Xunit; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.APIGatewayEvents; + +namespace HelloWorldAot.Tests; + +public class FunctionTest +{ + private static readonly HttpClient client = new HttpClient(); + + private static async Task GetCallingIP() + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var stringTask = client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + var msg = await stringTask; + return msg.Replace("\n",""); + } + + [Fact] + public async Task TestHelloWorldFunctionHandler() + { + var request = new APIGatewayHttpApiV2ProxyRequest(); + var context = new TestLambdaContext(); + string location = GetCallingIP().Result; + Dictionary body = new Dictionary + { + { "message", "hello world" }, + { "location", location }, + }; + + var expectedResponse = new APIGatewayHttpApiV2ProxyResponse + { + Body = JsonSerializer.Serialize(body), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + + var response = await Function.FunctionHandler(request, context); + + Console.WriteLine("Lambda Response: \n" + response.Body); + Console.WriteLine("Expected Response: \n" + expectedResponse.Body); + + Assert.Equal(expectedResponse.Body, response.Body); + Assert.Equal(expectedResponse.Headers, response.Headers); + Assert.Equal(expectedResponse.StatusCode, response.StatusCode); + } +} \ No newline at end of file diff --git a/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/HelloWorldAot.Tests.csproj b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/HelloWorldAot.Tests.csproj new file mode 100644 index 000000000..781680b47 --- /dev/null +++ b/dotnet10/hello-native-aot/{{cookiecutter.project_name}}/test/HelloWorldAot.Test/HelloWorldAot.Tests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + + + + + + + + + + + + + + + + + diff --git a/dotnet10/hello-pt/.gitignore b/dotnet10/hello-pt/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/hello-pt/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/hello-pt/Pipfile b/dotnet10/hello-pt/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/hello-pt/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/hello-pt/README.md b/dotnet10/hello-pt/README.md new file mode 100644 index 000000000..a9d7626d0 --- /dev/null +++ b/dotnet10/hello-pt/README.md @@ -0,0 +1,37 @@ +# AWS SAM cookiecutter for .NET 8 Lambda functions with Powertools for AWS Lambda (.NET) + +**Please note, you should not try to `git clone` this project.** Instead, use `cookiecutter` CLI instead as ``{{cookiecutter.project_name}}`` will be rendered based on your input and therefore all variables and files will be rendered properly. + +## Cookiecutter requirements + +Install `cookiecutter` command line: + +**Pip users**: + +* `pip install cookiecutter` + +**Homebrew users**: + +* `brew install cookiecutter` + +**Windows or Pipenv users**: + +* `pipenv install cookiecutter` + +**NOTE**: [`Pipenv`](https://github.com/pypa/pipenv) is the new and recommended Python packaging tool that works across multiple platforms and makes Windows a first-class citizen. + +### Usage + +Generate a new SAM based Serverless App: `sam init --runtime dotnet10`. + +You'll be prompted a few questions to help this cookiecutter template to scaffold this project and after its completed you should see a new folder at your current path with the name of the project you gave as input. + +**NOTE**: After you understand how cookiecutter works (cookiecutter.json, mainly), you can fork this repo and apply your own mechanisms to accelerate your development process and this can be followed for any programming language and OS. + +### Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) + +### License + +This project is licensed under the terms of the [MIT License with no attribution](/LICENSE) \ No newline at end of file diff --git a/dotnet10/hello-pt/cookiecutter.json b/dotnet10/hello-pt/cookiecutter.json new file mode 100644 index 000000000..f8090af32 --- /dev/null +++ b/dotnet10/hello-pt/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "SamAppPowertools for AWS Lambda", + "runtime": "dotnet10", + "architectures": { + "value": [ "x86_64", "arm64" ] + }, + "Powertools for AWS Lambda (.NET) Tracing": ["enabled","disabled"], + "Powertools for AWS Lambda (.NET) Metrics": ["enabled","disabled"], + "Powertools for AWS Lambda (.NET) Logging": ["enabled","disabled"], + "_copy_without_render": [ + ".gitignore" + ] +} diff --git a/dotnet10/hello-pt/setup.cfg b/dotnet10/hello-pt/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/hello-pt/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/hello-pt/tests/test_cookiecutter.py b/dotnet10/hello-pt/tests/test_cookiecutter.py new file mode 100644 index 000000000..987385e1f --- /dev/null +++ b/dotnet10/hello-pt/tests/test_cookiecutter.py @@ -0,0 +1,47 @@ +""" + Tests cookiecutter baking process and rendered content +""" + + +def test_project_tree(cookies): + result = cookies.bake(extra_context={ + 'project_name': 'hello sam' + }) + assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == 'hello sam' + assert result.project.isdir() + assert result.project.join('.gitignore').isfile() + assert result.project.join('template.yaml').isfile() + assert result.project.join('README.md').isfile() + assert result.project.join('src').isdir() + assert result.project.join('test').isdir() + assert result.project.join('src', 'HelloWorld').isdir() + assert result.project.join( + 'src', 'HelloWorld', 'HelloWorld.csproj').isfile() + assert result.project.join('src', 'HelloWorld', 'Function.cs').isfile() + assert result.project.join( + 'src', 'HelloWorld', 'aws-lambda-tools-defaults.json').isfile() + assert result.project.join( + 'test', 'HelloWorld.Test', 'FunctionTest.cs').isfile() + assert result.project.join( + 'test', 'HelloWorld.Test', 'HelloWorld.Tests.csproj').isfile() + + +def test_app_content(cookies): + result = cookies.bake(extra_context={'project_name': 'my_lambda'}) + app_file = result.project.join('src', 'HelloWorld', 'Function.cs') + app_content = app_file.readlines() + app_content = ''.join(app_content) + + contents = ( + "GetCallingIP", + "GetStringAsync", + "location", + "message", + "hello world", + "StatusCode" + ) + + for content in contents: + assert content in app_content diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/.gitignore b/dotnet10/hello-pt/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/README.md b/dotnet10/hello-pt/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..6c3635932 --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,166 @@ +# {{ cookiecutter.project_name }} + +Congratulations, you have just created a Serverless "Hello World" application using the AWS Serverless Application Model (AWS SAM) for the `dotnet10` runtime, and options to bootstrap it with [**Powertools for AWS Lambda (.NET)**](https://awslabs.github.io/aws-lambda-powertools-dotnet/) (Powertools) utilities for Logging, Tracing and Metrics. + +Powertools for AWS Lambda (.NET) is a developer toolkit to implement Serverless best practices and increase developer velocity. + +## Powertools for AWS Lambda (.NET) features + +Powertools for AWS Lambda (.NET) provides three core utilities: + +* **[Tracing](https://awslabs.github.io/aws-lambda-powertools-dotnet/core/tracer/)** - Decorators and utilities to trace Lambda function handlers, and both synchronous and asynchronous functions +* **[Logging](https://awslabs.github.io/aws-lambda-powertools-dotnet/core/logger/)** - Structured logging made easier, and decorator to enrich structured logging with key Lambda context details +* **[Metrics](https://awslabs.github.io/aws-lambda-powertools-dotnet/core/metrics/)** - Custom Metrics created asynchronously via CloudWatch Embedded Metric Format (EMF) + +Find the complete project's [documentation here](https://awslabs.github.io/aws-lambda-powertools-dotnet/). + +### Installing Powertools for AWS Lambda (.NET) + +Powertools for AWS Lambda utilities are available as NuGet packages. You can install the packages from the NuGet gallery or from within the Visual Studio IDE. Search `AWS.Lambda.Powertools*` to see various utilities available. Powertools for AWS Lambda (.NET) is available on NuGet. + +* [AWS.Lambda.Powertools.Logging](https://www.nuget.org/packages?q=AWS.Lambda.Powertools.Logging): + + `dotnet add package AWS.Lambda.Powertools.Logging` + +* [AWS.Lambda.Powertools.Metrics](https://www.nuget.org/packages?q=AWS.Lambda.Powertools.Metrics): + + `dotnet add package AWS.Lambda.Powertools.Metrics` + +* [AWS.Lambda.Powertools.Tracing](https://www.nuget.org/packages?q=AWS.Lambda.Powertools.Tracing): + + `dotnet add package AWS.Lambda.Powertools.Tracing` + +### Powertools for AWS Lambda (.NET) Examples + +We have provided examples focused specifically on each of the utilities. Each solution comes with an AWS Serverless Application Model (AWS SAM) templates to run your functions as a Zip package using the AWS Lambda .NET 8 managed runtime; or as a container package using the AWS base images for .NET. + +* **[Logging example](examples/Logging/)** +* **[Metrics example](examples/Metrics/)** +* **[Tracing example](examples/Tracing/)** + +## Working with this project + +This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. + +* src - Code for the application's Lambda function. +* events - Invocation events that you can use to invoke the function. +* test - Unit tests for the application code. +* template.yaml - A template that defines the application's AWS resources. + +The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started. + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +### Deploy the sample application + +The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the SAM CLI, you need the following tools. + +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) +* .NET 8 - [Install .NET 8](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +You can find your API Gateway Endpoint URL in the output values displayed after deployment. + +### Use the SAM CLI to build and test locally + +Build your application with the `sam build` command. + +```bash +{{ cookiecutter.project_name }}$ sam build +``` + +The SAM CLI installs dependencies defined in `src/HelloWorld.csproj`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{ cookiecutter.project_name }}$ sam local invoke HelloWorldFunction --event events/event.json +``` + +The SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000. + +```bash +{{ cookiecutter.project_name }}$ sam local start-api +{{ cookiecutter.project_name }}$ curl http://localhost:3000/ +``` + +The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path. + +```yaml + Events: + HelloWorld: + Type: Api + Properties: + Path: /hello + Method: get +``` + +### Add a resource to your application + +The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types. + +### Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. + +```bash +{{ cookiecutter.project_name }}$ sam logs -n HelloWorldFunction --stack-name {{ cookiecutter.project_name }} --tail +``` + +You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +### Unit tests + +Tests are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/HelloWorld.Test +``` + +### Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. + +Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/events/event.json b/dotnet10/hello-pt/{{cookiecutter.project_name}}/events/event.json new file mode 100644 index 000000000..3822fadaa --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/events/event.json @@ -0,0 +1,63 @@ +{ + "body": "{\"message\": \"hello world\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } + } + \ No newline at end of file diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/hello-pt/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs b/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs new file mode 100644 index 000000000..d6af41e38 --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; + +using Amazon.Lambda.Core; +using Amazon.Lambda.APIGatewayEvents; +{%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} +using AWS.Lambda.Powertools.Tracing; +{%- endif %} +{%- if cookiecutter["Powertools for AWS Lambda (.NET) Metrics"] == "enabled"%} +using AWS.Lambda.Powertools.Metrics; +{%- endif %} +{%- if cookiecutter["Powertools for AWS Lambda (.NET) Logging"] == "enabled"%} +using AWS.Lambda.Powertools.Logging; +{%- endif %} + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace HelloWorld; + +public class Function +{ + private static readonly HttpClient client = new HttpClient(); + + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} + public Function() + { + Tracing.RegisterForAllServices(); + } + {%- endif %} + + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} + [Tracing(SegmentName = "Get Calling IP")] + {%- endif %} + private static async Task GetCallingIP() + { + try + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var msg = await client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Metrics"] == "enabled"%} + // Custom Metric + // https://awslabs.github.io/aws-lambda-powertools-dotnet/core/metrics/ + Metrics.AddMetric("ApiRequestCount", 1, MetricUnit.Count); + {%- endif %} + + return msg.Replace("\n",""); + } + catch (Exception ex) + { + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Logging"] == "enabled" %} + Logger.LogError(ex); + {%- endif %} + throw; + } + } + + + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} + [Tracing(CaptureMode = TracingCaptureMode.ResponseAndError)] + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Metrics"] == "enabled"%} + [Metrics(CaptureColdStart = true)] + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Logging"] == "enabled"%} + [Logging(CorrelationIdPath = CorrelationIdPaths.ApiGatewayRest)] + {%- endif %} + public async Task FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) + { + + var location = await GetCallingIP(); + var body = new Dictionary + { + { "message", "hello world" }, + { "location", location } + }; + + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Logging"] == "enabled" %} + // Structured logging + // https://awslabs.github.io/aws-lambda-powertools-dotnet/core/logging/ + Logger.LogInformation("Hello world API - HTTP 200"); + {%- endif %} + + return new APIGatewayProxyResponse + { + Body = JsonSerializer.Serialize(body), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + } +} \ No newline at end of file diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj b/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj new file mode 100644 index 000000000..0a0280795 --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj @@ -0,0 +1,27 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} + + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Metrics"] == "enabled"%} + + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Logging"] == "enabled"%} + + {%- endif %} + + diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json b/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..ef79abab6 --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json @@ -0,0 +1,12 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "template": "template.yaml" +} \ No newline at end of file diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/template.yaml b/dotnet10/hello-pt/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..1b32da3cc --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,73 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Sample SAM Template with Powertools for AWS Lambda (.NET) for {{ cookiecutter.project_name }} + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 10 + MemorySize: 512 + Runtime: dotnet10 + Api: + # More info about OpenApiVersion: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-api.html#sam-api-openapiversion + OpenApiVersion: 3.0.1 + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} + TracingEnabled: true + {%- endif %} + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + Handler: HelloWorld::HelloWorld.Function::FunctionHandler + CodeUri: ./src/HelloWorld/ + Description: Hello World function w/ Powertools for AWS Lambda (.NET) # for more information on Powertools for AWS Lambda (.NET): https://github.com/awslabs/aws-lambda-powertools-dotnet + {%- if cookiecutter.architectures.value != []%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} + Tracing: Active + {%- endif %} + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled" or cookiecutter["Powertools for AWS Lambda (.NET) Logging"] == "enabled" %} + Environment: # Powertools env vars: https://awslabs.github.io/aws-lambda-powertools-python/#environment-variables + Variables: + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled" or cookiecutter["Powertools for AWS Lambda (.NET) Metrics"] == "enabled"%} + POWERTOOLS_SERVICE_NAME: PowertoolsHelloWorld + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Logging"] == "enabled"%} + POWERTOOLS_LOG_LEVEL: Info + POWERTOOLS_LOGGER_CASE: PascalCase # Allowed values are: CamelCase, PascalCase and SnakeCase (Default) + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Tracing"] == "enabled"%} + POWERTOOLS_TRACER_CAPTURE_RESPONSE: true + POWERTOOLS_TRACER_CAPTURE_ERROR: true # To disable tracing (CaptureMode = TracingCaptureMode.Disabled) + {%- endif %} + {%- if cookiecutter["Powertools for AWS Lambda (.NET) Metrics"] == "enabled"%} + POWERTOOLS_METRICS_NAMESPACE: {{ cookiecutter.project_name|lower|replace(' ', '-') }} + {%- endif %} + {%- endif %} + Tags: + LambdaPowertools: dotnet +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn \ No newline at end of file diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs b/dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs new file mode 100644 index 000000000..b103a46fc --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; +using Xunit; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.APIGatewayEvents; + +namespace HelloWorld.Tests; + +public class FunctionTest +{ + private static readonly HttpClient client = new HttpClient(); + + private static async Task GetCallingIP() + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var stringTask = client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + var msg = await stringTask; + return msg.Replace("\n",""); + } + + [Fact] + public async Task TestHelloWorldFunctionHandler() + { + Environment.SetEnvironmentVariable("POWERTOOLS_METRICS_NAMESPACE", "AWSLambdaPowertools"); // set dummy metrics namespace if env is unavailable + var request = new APIGatewayProxyRequest(); + var context = new TestLambdaContext(); + string location = GetCallingIP().Result; + Dictionary body = new Dictionary + { + { "message", "hello world" }, + { "location", location }, + }; + + var expectedResponse = new APIGatewayProxyResponse + { + Body = JsonSerializer.Serialize(body), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + + var function = new Function(); + var response = await function.FunctionHandler(request, context); + + Console.WriteLine("Lambda Response: \n" + response.Body); + Console.WriteLine("Expected Response: \n" + expectedResponse.Body); + + Assert.Equal(expectedResponse.Body, response.Body); + Assert.Equal(expectedResponse.Headers, response.Headers); + Assert.Equal(expectedResponse.StatusCode, response.StatusCode); + } +} \ No newline at end of file diff --git a/dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj b/dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj new file mode 100644 index 000000000..c95377008 --- /dev/null +++ b/dotnet10/hello-pt/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + + + + + + + + + + + + + + + + diff --git a/dotnet10/hello/.gitignore b/dotnet10/hello/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/hello/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/hello/Pipfile b/dotnet10/hello/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/hello/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/hello/README.md b/dotnet10/hello/README.md new file mode 100644 index 000000000..6fb16fa5b --- /dev/null +++ b/dotnet10/hello/README.md @@ -0,0 +1,39 @@ +# AWS SAM cookiecutter for .NET 8 Lambda functions + +This [cookiecutter](https://github.com/audreyr/cookiecutter) creates a "Hello World" application using the AWS Serverless Application Model (AWS SAM) with the `dotnet10` runtime. For more information on how to use this template, please see the generated project README file. + +**Please note, you should not try to `git clone` this project.** Instead, use `cookiecutter` CLI instead as ``{{cookiecutter.project_name}}`` will be rendered based on your input and therefore all variables and files will be rendered properly. + +## Cookiecutter requirements + +Install `cookiecutter` command line: + +**Pip users**: + +* `pip install cookiecutter` + +**Homebrew users**: + +* `brew install cookiecutter` + +**Windows or Pipenv users**: + +* `pipenv install cookiecutter` + +**NOTE**: [`Pipenv`](https://github.com/pypa/pipenv) is the new and recommended Python packaging tool that works across multiple platforms and makes Windows a first-class citizen. + +### Usage + +Generate a new SAM based Serverless App: `sam init --runtime dotnet10`. + +You'll be prompted a few questions to help this cookiecutter template to scaffold this project and after its completed you should see a new folder at your current path with the name of the project you gave as input. + +**NOTE**: After you understand how cookiecutter works (cookiecutter.json, mainly), you can fork this repo and apply your own mechanisms to accelerate your development process and this can be followed for any programming language and OS. + +### Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) + +### License + +This project is licensed under the terms of the [MIT License with no attribution](/LICENSE) \ No newline at end of file diff --git a/dotnet10/hello/cookiecutter.json b/dotnet10/hello/cookiecutter.json new file mode 100644 index 000000000..590d62b57 --- /dev/null +++ b/dotnet10/hello/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} diff --git a/dotnet10/hello/setup.cfg b/dotnet10/hello/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/hello/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/hello/tests/test_cookiecutter.py b/dotnet10/hello/tests/test_cookiecutter.py new file mode 100644 index 000000000..987385e1f --- /dev/null +++ b/dotnet10/hello/tests/test_cookiecutter.py @@ -0,0 +1,47 @@ +""" + Tests cookiecutter baking process and rendered content +""" + + +def test_project_tree(cookies): + result = cookies.bake(extra_context={ + 'project_name': 'hello sam' + }) + assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == 'hello sam' + assert result.project.isdir() + assert result.project.join('.gitignore').isfile() + assert result.project.join('template.yaml').isfile() + assert result.project.join('README.md').isfile() + assert result.project.join('src').isdir() + assert result.project.join('test').isdir() + assert result.project.join('src', 'HelloWorld').isdir() + assert result.project.join( + 'src', 'HelloWorld', 'HelloWorld.csproj').isfile() + assert result.project.join('src', 'HelloWorld', 'Function.cs').isfile() + assert result.project.join( + 'src', 'HelloWorld', 'aws-lambda-tools-defaults.json').isfile() + assert result.project.join( + 'test', 'HelloWorld.Test', 'FunctionTest.cs').isfile() + assert result.project.join( + 'test', 'HelloWorld.Test', 'HelloWorld.Tests.csproj').isfile() + + +def test_app_content(cookies): + result = cookies.bake(extra_context={'project_name': 'my_lambda'}) + app_file = result.project.join('src', 'HelloWorld', 'Function.cs') + app_content = app_file.readlines() + app_content = ''.join(app_content) + + contents = ( + "GetCallingIP", + "GetStringAsync", + "location", + "message", + "hello world", + "StatusCode" + ) + + for content in contents: + assert content in app_content diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/.gitignore b/dotnet10/hello/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/README.md b/dotnet10/hello/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..328bf538c --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,125 @@ +# {{ cookiecutter.project_name }} + +This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. + +- src - Code for the application's Lambda function. +- events - Invocation events that you can use to invoke the function. +- test - Unit tests for the application code. +- template.yaml - A template that defines the application's AWS resources. + +The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started. + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the SAM CLI, you need the following tools. + +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +You can find your API Gateway Endpoint URL in the output values displayed after deployment. + +## Use the SAM CLI to build and test locally + +Build your application with the `sam build` command. + +```bash +{{ cookiecutter.project_name }}$ sam build +``` + +The SAM CLI installs dependencies defined in `src/HelloWorld.csproj`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{ cookiecutter.project_name }}$ sam local invoke HelloWorldFunction --event events/event.json +``` + +The SAM CLI can also emulate your application's API. Use the `sam local start-api` to run the API locally on port 3000. + +```bash +{{ cookiecutter.project_name }}$ sam local start-api +{{ cookiecutter.project_name }}$ curl http://localhost:3000/ +``` + +The SAM CLI reads the application template to determine the API's routes and the functions that they invoke. The `Events` property on each function's definition includes the route and method for each path. + +```yaml + Events: + HelloWorld: + Type: Api + Properties: + Path: /hello + Method: get +``` + +## Add a resource to your application +The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. + +```bash +{{ cookiecutter.project_name }}$ sam logs -n HelloWorldFunction --stack-name {{ cookiecutter.project_name }} --tail +``` + +You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/HelloWorld.Test +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. + +Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/events/event.json b/dotnet10/hello/{{cookiecutter.project_name}}/events/event.json new file mode 100644 index 000000000..3822fadaa --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/events/event.json @@ -0,0 +1,63 @@ +{ + "body": "{\"message\": \"hello world\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } + } + \ No newline at end of file diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/hello/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs b/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs new file mode 100644 index 000000000..3a5e11009 --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/Function.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; + +using Amazon.Lambda.Core; +using Amazon.Lambda.APIGatewayEvents; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace HelloWorld; + +public class Function +{ + + private static readonly HttpClient client = new HttpClient(); + + private static async Task GetCallingIP() + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var msg = await client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + return msg.Replace("\n",""); + } + + public async Task FunctionHandler(APIGatewayProxyRequest apigProxyEvent, ILambdaContext context) + { + + var location = await GetCallingIP(); + var body = new Dictionary + { + { "message", "hello world" }, + { "location", location } + }; + + return new APIGatewayProxyResponse + { + Body = JsonSerializer.Serialize(body), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + } +} \ No newline at end of file diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj b/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj new file mode 100644 index 000000000..5dbd7f4bb --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/HelloWorld.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json b/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..ef79abab6 --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/src/HelloWorld/aws-lambda-tools-defaults.json @@ -0,0 +1,12 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "template": "template.yaml" +} \ No newline at end of file diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/template.yaml b/dotnet10/hello/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..4d4ad470e --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,48 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Sample SAM Template for {{ cookiecutter.project_name }} + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 10 + MemorySize: 512 + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: ./src/HelloWorld/ + Handler: HelloWorld::HelloWorld.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + MemorySize: 512 + Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object + Variables: + PARAM1: VALUE + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: "API Gateway endpoint URL for Prod stage for Hello World function" + Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/Prod/hello/" + HelloWorldFunction: + Description: "Hello World Lambda Function ARN" + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: "Implicit IAM Role created for Hello World function" + Value: !GetAtt HelloWorldFunctionRole.Arn diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs b/dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs new file mode 100644 index 000000000..e36d3c66f --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/FunctionTest.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Net.Http; +using System.Text.Json; +using Xunit; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.APIGatewayEvents; + +namespace HelloWorld.Tests; + +public class FunctionTest +{ + private static readonly HttpClient client = new HttpClient(); + + private static async Task GetCallingIP() + { + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Add("User-Agent", "AWS Lambda .Net Client"); + + var stringTask = client.GetStringAsync("http://checkip.amazonaws.com/").ConfigureAwait(continueOnCapturedContext:false); + + var msg = await stringTask; + return msg.Replace("\n",""); + } + + [Fact] + public async Task TestHelloWorldFunctionHandler() + { + var request = new APIGatewayProxyRequest(); + var context = new TestLambdaContext(); + string location = GetCallingIP().Result; + Dictionary body = new Dictionary + { + { "message", "hello world" }, + { "location", location }, + }; + + var expectedResponse = new APIGatewayProxyResponse + { + Body = JsonSerializer.Serialize(body), + StatusCode = 200, + Headers = new Dictionary { { "Content-Type", "application/json" } } + }; + + var function = new Function(); + var response = await function.FunctionHandler(request, context); + + Console.WriteLine("Lambda Response: \n" + response.Body); + Console.WriteLine("Expected Response: \n" + expectedResponse.Body); + + Assert.Equal(expectedResponse.Body, response.Body); + Assert.Equal(expectedResponse.Headers, response.Headers); + Assert.Equal(expectedResponse.StatusCode, response.StatusCode); + } +} \ No newline at end of file diff --git a/dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj b/dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj new file mode 100644 index 000000000..c95377008 --- /dev/null +++ b/dotnet10/hello/{{cookiecutter.project_name}}/test/HelloWorld.Test/HelloWorld.Tests.csproj @@ -0,0 +1,20 @@ + + + + net10.0 + + + + + + + + + + + + + + + + diff --git a/dotnet10/s3/.gitignore b/dotnet10/s3/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/s3/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/s3/Pipfile b/dotnet10/s3/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/s3/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/s3/README.md b/dotnet10/s3/README.md new file mode 100644 index 000000000..443900bc5 --- /dev/null +++ b/dotnet10/s3/README.md @@ -0,0 +1,19 @@ +# Cookiecutter .NET 8 S3 Quick Start Application + +A cookiecutter template to create a dotnet S3 Quick Start Application using [Serverless Application Model (SAM)](https://github.com/awslabs/serverless-application-model). + +## Requirements + +* [AWS SAM CLI](https://github.com/awslabs/aws-sam-cli) + +## Usage + +Generate a boilerplate template in your current project directory using the following syntax: + +* **.NET 8**: `sam init --runtime dotnet10 --app-template quick-start-s3 --name s3-app` + +> **NOTE**: ``--name`` allows you to specify a different project folder name + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) diff --git a/dotnet10/s3/cookiecutter.json b/dotnet10/s3/cookiecutter.json new file mode 100644 index 000000000..590d62b57 --- /dev/null +++ b/dotnet10/s3/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} diff --git a/dotnet10/s3/setup.cfg b/dotnet10/s3/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/s3/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/.gitignore b/dotnet10/s3/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/README.md b/dotnet10/s3/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..90d5b650d --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,153 @@ +# {{ cookiecutter.project_name }} + +This project contains source code and supporting files for a serverless application that you can deploy with the AWS Serverless Application Model (AWS SAM) command line interface (CLI). It includes the following files and folders: + +- `src` - Code for the application's Lambda function. +- `events` - Invocation events that you can use to invoke the function. +- `__tests__` - Unit tests for the application code. +- `template.yaml` - A template that defines the application's AWS resources. + +Resources for this project are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open-source plugin for popular IDEs that uses the AWS SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds step-through debugging for Lambda function code. + +To get started, see the following: + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The AWS SAM CLI is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the AWS SAM CLI, you need the following tools: + +* AWS SAM CLI - [Install the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download). +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community). + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Parameter AppBucketName**: This template includes a parameter to name the S3 bucket you will create as a part of the new application. This name needs to be globally unique. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +## Use the AWS SAM CLI to build and test locally + +Build your application by using the `sam build` command. + +```bash +sam build +``` + +The AWS SAM CLI installs dependencies that are defined in `package.json`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +sam local invoke S3JsonLoggerFunction --event events/event-s3.json +``` + +## Add a resource to your application + +The application template uses AWS SAM to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources, such as functions, triggers, and APIs. For resources that aren't included in the [AWS SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use the standard [AWS CloudFormation resource types](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html). + +Update `template.yaml` to add a dead-letter queue to your application. In the **Resources** section, add a resource named **MyQueue** with the type **AWS::SQS::Queue**. Then add a property to the **AWS::Serverless::Function** resource named **DeadLetterQueue** that targets the queue's Amazon Resource Name (ARN), and a policy that grants the function permission to access the queue. + +```yaml +Resources: + MyQueue: + Type: AWS::SQS::Queue + S3JsonLoggerFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src/S3EventSource/ + Handler: S3EventSource::S3EventSource.Function::FunctionHandler + Runtime: dotnet10 + MemorySize: 512 + DeadLetterQueue: + Type: SQS + TargetArn: !GetAtt MyQueue.Arn + Policies: + - SQSSendMessagePolicy: + QueueName: !GetAtt MyQueue.QueueName + - S3NewObjectEvent: + Type: S3 + Properties: + Bucket: !Ref AppBucket + Events: s3:ObjectCreated:* + Filter: + S3Key: + Rules: + - Name: suffix + Value: ".json" +``` + +The dead-letter queue is a location for Lambda to send events that could not be processed. It's only used if you invoke your function asynchronously, but it's useful here to show how you can modify your application's resources and function configuration. + +Deploy the updated application. + +```bash +sam build +sam deploy +``` + +Open the [**Applications**](https://console.aws.amazon.com/lambda/home#/applications) page of the Lambda console, and choose your application. When the deployment completes, view the application resources on the **Overview** tab to see the new resource. Then, choose the function to see the updated configuration that specifies the dead-letter queue. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, the AWS SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs that are generated by your Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +**NOTE:** This command works for all Lambda functions, not just the ones you deploy using AWS SAM. + +```bash +sam logs -n S3JsonLoggerFunction --stack-name {{ cookiecutter.project_name }} --tail +``` + +**NOTE:** This uses the logical name of the function within the stack. This is the correct name to use when searching logs inside an AWS Lambda function within a CloudFormation stack, even if the deployed function name varies due to CloudFormation's unique resource name generation. + +You can find more information and examples about filtering Lambda function logs in the [AWS SAM CLI documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests are defined in the `test` folder in this project. + +```bash +dotnet test test/{{ cookiecutter.project_name }}.Tests/{{ cookiecutter.project_name }}.Tests.csproj +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +For an introduction to the AWS SAM specification, the AWS SAM CLI, and serverless application concepts, see the [AWS SAM Developer Guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html). + +Next, you can use the AWS Serverless Application Repository to deploy ready-to-use apps that go beyond Hello World samples and learn how authors developed their applications. For more information, see the [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) and the [AWS Serverless Application Repository Developer Guide](https://docs.aws.amazon.com/serverlessrepo/latest/devguide/what-is-serverlessrepo.html). diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/events/event.json b/dotnet10/s3/{{cookiecutter.project_name}}/events/event.json new file mode 100644 index 000000000..d1fbf3409 --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/events/event.json @@ -0,0 +1,38 @@ +{ + "Records": [ + { + "eventVersion": "2.0", + "eventSource": "aws:s3", + "awsRegion": "us-east-1", + "eventTime": "1970-01-01T00:00:00.000Z", + "eventName": "ObjectCreated:Put", + "userIdentity": { + "principalId": "EXAMPLE" + }, + "requestParameters": { + "sourceIPAddress": "127.0.0.1" + }, + "responseElements": { + "x-amz-request-id": "EXAMPLE123456789", + "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH" + }, + "s3": { + "s3SchemaVersion": "1.0", + "configurationId": "testConfigRule", + "bucket": { + "name": "example-bucket", + "ownerIdentity": { + "principalId": "EXAMPLE" + }, + "arn": "arn:aws:s3:::example-bucket" + }, + "object": { + "key": "test/key", + "size": 1024, + "eTag": "0123456789abcdef0123456789abcdef", + "sequencer": "0A1B2C3D4E5F678901" + } + } + } + ] +} \ No newline at end of file diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/s3/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/Function.cs b/dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/Function.cs new file mode 100644 index 000000000..e43969e51 --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/Function.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Text.Json; + +using Amazon.Lambda.Core; +using Amazon.Lambda.S3Events; +using Amazon.S3; +using Amazon.S3.Util; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace S3EventSource; + +public class Function +{ + IAmazonS3 S3Client { get; set; } + + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public Function() + { + S3Client = new AmazonS3Client(); + } + + /// + /// Constructs an instance with a preconfigured S3 client. This can be used for testing the outside of the Lambda environment. + /// + /// + public Function(IAmazonS3 s3Client) + { + this.S3Client = s3Client; + } + + /// + /// This method is called for every Lambda invocation. This method takes in an S3 event object and can be used + /// to respond to S3 notifications. + /// + /// + /// + /// + public async Task FunctionHandler(S3Event evnt, ILambdaContext context) + { + var s3Event = evnt.Records?[0].S3; + if(s3Event == null) + { + return null; + } + + try + { + var response = await this.S3Client.GetObjectMetadataAsync(s3Event.Bucket.Name, s3Event.Object.Key); + context.Logger.LogLine($"S3 Object Key: {s3Event.Object.Key}"); + context.Logger.LogLine(JsonSerializer.Serialize(response)); + return response.Headers.ContentType; + } + catch(Exception e) + { + context.Logger.LogLine($"Error getting object {s3Event.Object.Key} from bucket {s3Event.Bucket.Name}. Make sure they exist and your bucket is in the same region as this function."); + context.Logger.LogLine(e.Message); + context.Logger.LogLine(e.StackTrace); + throw; + } + } +} \ No newline at end of file diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/S3EventSource.csproj b/dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/S3EventSource.csproj new file mode 100644 index 000000000..4a6023cbf --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/src/S3EventSource/S3EventSource.csproj @@ -0,0 +1,19 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + + \ No newline at end of file diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/template.yaml b/dotnet10/s3/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..d4172b452 --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,53 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Sample SAM Template for {{ cookiecutter.project_name }} + +Parameters: + AppBucketName: + Type: String + Description: "REQUIRED: Unique S3 bucket name to use for the app." + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 10 + MemorySize: 512 + +Resources: + S3JsonLoggerFunction: + # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src/S3EventSource/ + Handler: S3EventSource::S3EventSource.Function::FunctionHandler + Runtime: dotnet10 + MemorySize: 512 + Policies: + S3ReadPolicy: + BucketName: !Ref AppBucketName + Events: + S3NewObjectEvent: + Type: S3 + Properties: + Bucket: !Ref AppBucket + Events: s3:ObjectCreated:* + Filter: + S3Key: + Rules: + - Name: suffix + Value: ".json" + AppBucket: + Type: AWS::S3::Bucket + Properties: + BucketName: !Ref AppBucketName + BucketEncryption: + ServerSideEncryptionConfiguration: + - BucketKeyEnabled: true + VersioningConfiguration: + Status: Enabled + +Outputs: + AppBucketArn: + Description: "S3 Bucket" + Value: !Ref AppBucket diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/FunctionTest.cs b/dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/FunctionTest.cs new file mode 100644 index 000000000..dc799ef0c --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/FunctionTest.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +using Xunit; +using Moq; +using Amazon.Lambda; +using Amazon.Lambda.Core; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.S3Events; + +using Amazon; +using Amazon.S3; +using Amazon.S3.Model; +using Amazon.S3.Util; + +using S3EventSource; + +namespace S3EventSource.Tests; + +public class FunctionTest +{ + [Fact] + public async Task TestS3EventLambdaFunction() + { + var context = new TestLambdaContext(); + + var bucketName = "lambda-S3JsonLogger-".ToLower() + DateTime.Now.Ticks; + var key = "text.txt"; + + // BEGIN mocking s3Client + var s3ClientMock = new Mock(); + s3ClientMock.Setup(x => x.Config) + .Returns(new AmazonS3Config { RegionEndpoint = RegionEndpoint.USWest2 }); + + var response = new GetObjectMetadataResponse(); + response.Headers.ContentType = "text/plain"; + response.Expires = DateTime.Now; + + s3ClientMock.Setup(x => x.GetObjectMetadataAsync( + It.Is(_bucketName => _bucketName == bucketName), // Mock with the given bucket name + It.Is(_key => _key == key), // Mock with the given key + It.IsAny()) + ) + .Returns(Task.FromResult(response)); + + var s3Client = s3ClientMock.Object; + // END mocking s3Client + + + // Setup the S3 event object that S3 notifications would create with the fields used by the Lambda function. + var s3Event = new S3Event + { + Records = new List + { + new S3EventNotification.S3EventNotificationRecord + { + S3 = new S3EventNotification.S3Entity + { + Bucket = new S3EventNotification.S3BucketEntity { Name = bucketName }, + Object = new S3EventNotification.S3ObjectEntity { Key = key } + } + } + } + }; + + // Invoke the lambda function and confirm the content type was returned. + var function = new Function(s3Client); + var contentType = await function.FunctionHandler(s3Event, context); + + Assert.Equal("text/plain", contentType); + } +} \ No newline at end of file diff --git a/dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/S3Event.Tests.csproj b/dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/S3Event.Tests.csproj new file mode 100644 index 000000000..4877d5ec9 --- /dev/null +++ b/dotnet10/s3/{{cookiecutter.project_name}}/test/S3EventSource.Tests/S3Event.Tests.csproj @@ -0,0 +1,18 @@ + + + net10.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dotnet10/scratch/.gitignore b/dotnet10/scratch/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/scratch/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/scratch/Pipfile b/dotnet10/scratch/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/scratch/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/scratch/README.md b/dotnet10/scratch/README.md new file mode 100644 index 000000000..52465cc3a --- /dev/null +++ b/dotnet10/scratch/README.md @@ -0,0 +1,15 @@ +# Cookiecutter .NET 8 "From Scratch" Quick Start Application + +A cookiecutter template to create a .NET 8 Basic Quick Start Application using [Serverless Application Model (SAM)](https://github.com/awslabs/serverless-application-model). + +## Requirements + +* [AWS SAM CLI](https://github.com/awslabs/aws-sam-cli) + +## Usage + +Access this template by running `sam init` and choosing it from the list of available templates. + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) \ No newline at end of file diff --git a/dotnet10/scratch/cookiecutter.json b/dotnet10/scratch/cookiecutter.json new file mode 100644 index 000000000..457876204 --- /dev/null +++ b/dotnet10/scratch/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} \ No newline at end of file diff --git a/dotnet10/scratch/setup.cfg b/dotnet10/scratch/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/scratch/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/.gitignore b/dotnet10/scratch/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/README.md b/dotnet10/scratch/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..9e06a4d40 --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,141 @@ +# {{cookiecutter.project_name}} + +This project contains source code and supporting files for a serverless application that you can deploy with the AWS Serverless Application Model (AWS SAM) command line interface (CLI). It includes the following files and folders: + +- `src` - Code for the application's Lambda function. +- `test` - Unit tests for the application code. +- `template.yaml` - A template that defines the application's AWS resources. + +Resources for this project are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open-source plugin for popular IDEs that uses the AWS SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds step-through debugging for Lambda function code. + +To get started, see the following: + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The AWS SAM CLI is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the AWS SAM CLI, you need the following tools: + +* AWS SAM CLI - [Install the AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html). +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community). + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +## Use the AWS SAM CLI to build and test locally + +Build your application by using the `sam build` command. + +```bash +{{cookiecutter.project_name}}$ sam build +``` + +The AWS SAM CLI installs dependencies that are defined in `package.json`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{cookiecutter.project_name}}$ sam local invoke helloFromLambdaFunction --no-event +``` + +## Add a resource to your application + +The application template uses AWS SAM to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources, such as functions, triggers, and APIs. For resources that aren't included in the [AWS SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use the standard [AWS CloudFormation resource types](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html). + +Update `template.yaml` to add a dead-letter queue to your application. In the **Resources** section, add a resource named **MyQueue** with the type **AWS::SQS::Queue**. Then add a property to the **AWS::Serverless::Function** resource named **DeadLetterQueue** that targets the queue's Amazon Resource Name (ARN), and a policy that grants the function permission to access the queue. + +```yaml +Resources: + MyQueue: + Type: AWS::SQS::Queue + helloFromLambdaFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src/ScratchLambda/ + Handler: ScratchLambda::ScratchLambda.Function::FunctionHandler + Runtime: dotnet10 + MemorySize: 512 + Timeout: 100 + DeadLetterQueue: + Type: SQS + TargetArn: !GetAtt MyQueue.Arn + Policies: + - SQSSendMessagePolicy: + QueueName: !GetAtt MyQueue.QueueName +``` + +The dead-letter queue is a location for Lambda to send events that could not be processed. It's only used if you invoke your function asynchronously, but it's useful here to show how you can modify your application's resources and function configuration. + +Deploy the updated application. + +```bash +{{cookiecutter.project_name}}$ sam deploy +``` + +Open the [**Applications**](https://console.aws.amazon.com/lambda/home#/applications) page of the Lambda console, and choose your application. When the deployment completes, view the application resources on the **Overview** tab to see the new resource. Then, choose the function to see the updated configuration that specifies the dead-letter queue. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, the AWS SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs that are generated by your Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +**NOTE:** This command works for all Lambda functions, not just the ones you deploy using AWS SAM. + +```bash +{{cookiecutter.project_name}}$ sam logs -n helloFromLambdaFunction --stack-name sam-app --tail +``` + +**NOTE:** This uses the logical name of the function within the stack. This is the correct name to use when searching logs inside an AWS Lambda function within a CloudFormation stack, even if the deployed function name varies due to CloudFormation's unique resource name generation. + +You can find more information and examples about filtering Lambda function logs in the [AWS SAM CLI documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests for the Lambda functions are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/{{ cookiecutter.project_name }}.Tests/{{ cookiecutter.project_name }}.Tests.csproj +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +For an introduction to the AWS SAM specification, the AWS SAM CLI, and serverless application concepts, see the [AWS SAM Developer Guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html). + +Next, you can use the AWS Serverless Application Repository to deploy ready-to-use apps that go beyond Hello World samples and learn how authors developed their applications. For more information, see the [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) and the [AWS Serverless Application Repository Developer Guide](https://docs.aws.amazon.com/serverlessrepo/latest/devguide/what-is-serverlessrepo.html). diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/scratch/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..fde486c41 --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/Function.cs b/dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/Function.cs new file mode 100644 index 000000000..ab273918c --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/Function.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Amazon.Lambda.Core; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace ScratchLambda; + +public class Function +{ + + /// + /// A simple function that takes a string and does a ToUpper + /// + /// + /// + /// + public string FunctionHandler(string input, ILambdaContext context) + { + var message = input ?? "Hello from Lambda!"; + // All log statements are written to CloudWatch by default. For more information, see + // https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-logging.html + context.Logger.LogLine($"Processed message: {message}"); + return message.ToUpper(); + } +} \ No newline at end of file diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/ScratchLambda.csproj b/dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/ScratchLambda.csproj new file mode 100644 index 000000000..022450073 --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/src/ScratchLambda/ScratchLambda.csproj @@ -0,0 +1,17 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + \ No newline at end of file diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/template.yaml b/dotnet10/scratch/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..6afe3ae53 --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,40 @@ +# This is the SAM template that represents the architecture of your serverless application +# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template-basics.html + +# The AWSTemplateFormatVersion identifies the capabilities of the template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html +AWSTemplateFormatVersion: 2010-09-09 +Description: >- + {{cookiecutter.project_name}} + +# Transform section specifies one or more macros that AWS CloudFormation uses to process your template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html +Transform: +- AWS::Serverless-2016-10-31 + +# Resources declares the AWS resources that you want to include in the stack +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html +Resources: + # Each Lambda function is defined by properties: + # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + + # This is a Lambda function config associated with the source code: hello-from-lambda.js + helloFromLambdaFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src/ScratchLambda/ + Handler: ScratchLambda::ScratchLambda.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + MemorySize: 512 + Timeout: 100 + Description: A Lambda function that returns a static string. + Policies: + # Give Lambda basic execution Permission to the helloFromLambda + - AWSLambdaBasicExecutionRole + diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/FunctionTest.cs b/dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/FunctionTest.cs new file mode 100644 index 000000000..a239c153b --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/FunctionTest.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +using Xunit; +using Amazon.Lambda.Core; +using Amazon.Lambda.TestUtilities; + +using ScratchLambda; + +namespace ScratchLambda.Tests; + +public class FunctionTest +{ + [Fact] + public void TestToUpperFunction() + { + + // Invoke the lambda function and confirm the string was upper cased. + var function = new Function(); + var context = new TestLambdaContext(); + var upperCase = function.FunctionHandler("hello world", context); + + Assert.Equal("HELLO WORLD", upperCase); + } +} \ No newline at end of file diff --git a/dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/ScratchLambda.Tests.csproj b/dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/ScratchLambda.Tests.csproj new file mode 100644 index 000000000..4f929fb64 --- /dev/null +++ b/dotnet10/scratch/{{cookiecutter.project_name}}/test/ScratchLambda.Tests/ScratchLambda.Tests.csproj @@ -0,0 +1,15 @@ + + + net10.0 + + + + + + + + + + + + \ No newline at end of file diff --git a/dotnet10/sns/.gitignore b/dotnet10/sns/.gitignore new file mode 100644 index 000000000..6c30741aa --- /dev/null +++ b/dotnet10/sns/.gitignore @@ -0,0 +1,170 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +obj/ +bin/ + +# End of https://www.gitignore.io/api/osx,linux,python,windows diff --git a/dotnet10/sns/Pipfile b/dotnet10/sns/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/sns/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/sns/README.md b/dotnet10/sns/README.md new file mode 100644 index 000000000..f29f9a115 --- /dev/null +++ b/dotnet10/sns/README.md @@ -0,0 +1,15 @@ +# Cookiecutter .NET 8 SNS Quick Start Application + +A cookiecutter template to create a .NET 8 SNS Quick Start Application using [Serverless Application Model (SAM)](https://github.com/awslabs/serverless-application-model). + +## Requirements + +* [AWS SAM CLI](https://github.com/awslabs/aws-sam-cli) + +## Usage + +Access this template by running `sam init` and choosing it from the list of available templates. + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) \ No newline at end of file diff --git a/dotnet10/sns/cookiecutter.json b/dotnet10/sns/cookiecutter.json new file mode 100644 index 000000000..457876204 --- /dev/null +++ b/dotnet10/sns/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} \ No newline at end of file diff --git a/dotnet10/sns/setup.cfg b/dotnet10/sns/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/sns/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Function.cs b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Function.cs new file mode 100644 index 000000000..b1a80db04 --- /dev/null +++ b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Function.cs @@ -0,0 +1,45 @@ +using Amazon.Lambda.Core; +using Amazon.Lambda.SNSEvents; + + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace SNSEventSource; + +public class Function +{ + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public Function() + { + + } + + + /// + /// This method is called for every Lambda invocation. This method takes in an SNS event object and can be used + /// to respond to SNS messages. + /// + /// + /// + /// + public async Task FunctionHandler(SNSEvent evnt, ILambdaContext context) + { + foreach(var record in evnt.Records) + { + await ProcessRecordAsync(record, context); + } + } + + private async Task ProcessRecordAsync(SNSEvent.SNSRecord record, ILambdaContext context) + { + context.Logger.LogInformation($"Processed record {record.Sns.Message}"); + + // TODO: Do interesting work based on the new message + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Readme.md b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Readme.md new file mode 100644 index 000000000..17c925515 --- /dev/null +++ b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/Readme.md @@ -0,0 +1,51 @@ +# AWS Lambda Simple SNS Function Project + +This starter project consists of: +* Function.cs - class file containing a class with a single function handler method +* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS + +You may also have a test project depending on the options selected. + +The generated function handler responds to events on an Amazon SNS service. + +After deploying your function you must configure an Amazon SNS service as an event source to trigger your Lambda function. + +## Here are some steps to follow from Visual Studio: + +To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. + +To view your deployed function open its Function View window by double-clicking the function name shown beneath the AWS Lambda node in the AWS Explorer tree. + +To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. + +To configure event sources for your deployed function use the Event Sources tab in the opened Function View window. + +To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. + +To view execution logs of invocations of your function use the Logs tab in the opened Function View window. + +## Here are some steps to follow to get started from the command line: + +Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. + +Install Amazon.Lambda.Tools Global Tools if not already installed. +``` + dotnet tool install -g Amazon.Lambda.Tools +``` + +If already installed check if new version is available. +``` + dotnet tool update -g Amazon.Lambda.Tools +``` + +Execute unit tests +``` + cd "{{cookiecutter.project_name}}/test/{{cookiecutter.project_name}}.Tests" + dotnet test +``` + +Deploy function to AWS Lambda +``` + cd "{{cookiecutter.project_name}}/src/{{cookiecutter.project_name}}" + dotnet lambda deploy-function +``` diff --git a/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/SNSEventSource.csproj b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/SNSEventSource.csproj new file mode 100644 index 000000000..f2bcf5d78 --- /dev/null +++ b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/SNSEventSource.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + \ No newline at end of file diff --git a/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/aws-lambda-tools-defaults.json b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..5aa2bf406 --- /dev/null +++ b/dotnet10/sns/{{cookiecutter.project_name}}/src/SNSEventSource/aws-lambda-tools-defaults.json @@ -0,0 +1,15 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "function-runtime": "dotnet10", + "function-memory-size": 512, + "function-timeout": 30, + "function-handler": "SNSEventSource::SNSEventSource.Function::FunctionHandler" +} \ No newline at end of file diff --git a/dotnet10/sns/{{cookiecutter.project_name}}/template.yaml b/dotnet10/sns/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..402e176ac --- /dev/null +++ b/dotnet10/sns/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,58 @@ +# This is the SAM template that represents the architecture of your serverless application +# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template-basics.html + +# The AWSTemplateFormatVersion identifies the capabilities of the template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html +AWSTemplateFormatVersion: 2010-09-09 +Description: >- + {{cookiecutter.project_name}} + Sample SAM Template for {{ cookiecutter.project_name }} + +# Transform section specifies one or more macros that AWS CloudFormation uses to process your template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html +Transform: +- AWS::Serverless-2016-10-31 + +Globals: + Function: + Timeout: 100 + +# Resources declares the AWS resources that you want to include in the stack +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html +Resources: + # This is an SNS Topic with all default configuration properties. To learn more about the available options, see + # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html + SimpleTopic: + Type: AWS::SNS::Topic + + # This is the Lambda function definition associated with the source code: sns-payload-logger.js. For all available properties, see + # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + SNSPayloadLogger: + Type: AWS::Serverless::Function + Properties: + Description: A Lambda function that logs the payload of messages sent to an associated SNS topic. + CodeUri: ./src/SNSEventSource/ + Handler: SNSEventSource::SNSEventSource.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + MemorySize: 512 + # This property associates this Lambda function with the SNS topic defined above, so that whenever the topic + # receives a message, the Lambda function is invoked + Events: + SNSTopicEvent: + Type: SNS + Properties: + Topic: !Ref SimpleTopic + Policies: + # Give Lambda basic execution Permission to the helloFromLambda + - AWSLambdaBasicExecutionRole + +Outputs: + AppBucketArn: + Description: "SNS Topic ARN" + Value: !Ref SimpleTopic \ No newline at end of file diff --git a/dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/FunctionTest.cs b/dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/FunctionTest.cs new file mode 100644 index 000000000..ac56bad7a --- /dev/null +++ b/dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/FunctionTest.cs @@ -0,0 +1,37 @@ +using Xunit; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.SNSEvents; + +namespace SNSEventSource.Tests; + +public class FunctionTest +{ + [Fact] + public async Task TestSQSEventLambdaFunction() + { + var snsEvent = new SNSEvent + { + Records = new List + { + new SNSEvent.SNSRecord + { + Sns = new SNSEvent.SNSMessage() + { + Message = "foobar" + } + } + } + }; + + var logger = new TestLambdaLogger(); + var context = new TestLambdaContext + { + Logger = logger + }; + + var function = new Function(); + await function.FunctionHandler(snsEvent, context); + + Assert.Contains("Processed record foobar", logger.Buffer.ToString()); + } +} \ No newline at end of file diff --git a/dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/SNSEventSource.Tests.csproj b/dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/SNSEventSource.Tests.csproj new file mode 100644 index 000000000..c1ad54f1e --- /dev/null +++ b/dotnet10/sns/{{cookiecutter.project_name}}/test/SNSEventSource.Tests/SNSEventSource.Tests.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + + + + + + + + + + + + + \ No newline at end of file diff --git a/dotnet10/sqs/.gitignore b/dotnet10/sqs/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/sqs/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/sqs/Pipfile b/dotnet10/sqs/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/sqs/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/sqs/README.md b/dotnet10/sqs/README.md new file mode 100644 index 000000000..8675762b9 --- /dev/null +++ b/dotnet10/sqs/README.md @@ -0,0 +1,17 @@ +# Cookiecutter dotNet Step Functions Sample App (Stock Trader) for SAM based Serverless App + +A cookiecutter template to create a dotNet Step Functions Sample App (Stock Trader) boilerplate using [Serverless Application Model (SAM)](https://github.com/awslabs/serverless-application-model). + +This application creates a stock trading workflow which runs on a pre-defined schedule. It demonstrates the power of Step Functions to orchestrate Lambda functions and other AWS resources to form complex and robust workflows, coupled with event-driven development using Amazon EventBridge. + +## Requirements + +* [AWS SAM CLI](https://github.com/awslabs/aws-sam-cli) + +## Usage + +Access this template by running `sam init` and choosing it from the list of available templates. + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) \ No newline at end of file diff --git a/dotnet10/sqs/cookiecutter.json b/dotnet10/sqs/cookiecutter.json new file mode 100644 index 000000000..590d62b57 --- /dev/null +++ b/dotnet10/sqs/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} diff --git a/dotnet10/sqs/setup.cfg b/dotnet10/sqs/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/sqs/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/.gitignore b/dotnet10/sqs/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..687ed019d --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,406 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode +vsdbg/ \ No newline at end of file diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/README.md b/dotnet10/sqs/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..da4274388 --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,141 @@ +# {{cookiecutter.project_name}} + +This project contains source code and supporting files for a serverless application that you can deploy with the AWS Serverless Application Model (AWS SAM) command line interface (CLI). It includes the following files and folders: + +- `src` - Code for the application's Lambda function. +- `events` - Invocation events that you can use to invoke the function. +- `test` - Unit tests for the application code. +- `template.yaml` - A template that defines the application's AWS resources. + +Resources for this project are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open-source plugin for popular IDEs that uses the AWS SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds step-through debugging for Lambda function code. + +To get started, see the following: + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The AWS SAM CLI is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the AWS SAM CLI, you need the following tools: + +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) +* .NET 8 - [Install .NET 8](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +## Use the AWS SAM CLI to build and test locally + +Build your application by using the `sam build` command. + +```bash +{{cookiecutter.project_name}}$ sam build +``` + +The AWS SAM CLI installs dependencies that are defined in `package.json`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{cookiecutter.project_name}}$ sam local invoke SQSPayloadLogger --event events/event-sqs.json +``` + +## Add a resource to your application + +The application template uses AWS SAM to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources, such as functions, triggers, and APIs. For resources that aren't included in the [AWS SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use the standard [AWS CloudFormation resource types](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html). + +Update `template.yaml` to add a dead-letter queue to your application. In the **Resources** section, add a resource named **MyQueue** with the type **AWS::SQS::Queue**. Then add a property to the **AWS::Serverless::Function** resource named **DeadLetterQueue** that targets the queue's Amazon Resource Name (ARN), and a policy that grants the function permission to access the queue. + +``` +Resources: + MyQueue: + Type: AWS::SQS::Queue + SQSPayloadLogger: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src/SQSEventSource/ + Handler: SQSEventSource::SQSEventSource.Function::FunctionHandler + Runtime: dotnet10 + MemorySize: 512 + DeadLetterQueue: + Type: SQS + TargetArn: !GetAtt MyQueue.Arn + Policies: + - SQSSendMessagePolicy: + QueueName: !GetAtt MyQueue.QueueName +``` + +The dead-letter queue is a location for Lambda to send events that could not be processed. It's only used if you invoke your function asynchronously, but it's useful here to show how you can modify your application's resources and function configuration. + +Deploy the updated application. + +```bash +{{cookiecutter.project_name}}$ sam deploy +``` + +Open the [**Applications**](https://console.aws.amazon.com/lambda/home#/applications) page of the Lambda console, and choose your application. When the deployment completes, view the application resources on the **Overview** tab to see the new resource. Then, choose the function to see the updated configuration that specifies the dead-letter queue. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, the AWS SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs that are generated by your Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +**NOTE:** This command works for all Lambda functions, not just the ones you deploy using AWS SAM. + +```bash +{{cookiecutter.project_name}}$ sam logs -n SQSPayloadLogger --stack-name sam-app --tail +``` + +**NOTE:** This uses the logical name of the function within the stack. This is the correct name to use when searching logs inside an AWS Lambda function within a CloudFormation stack, even if the deployed function name varies due to CloudFormation's unique resource name generation. + +You can find more information and examples about filtering Lambda function logs in the [AWS SAM CLI documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests for the Lambda functions are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/{{ cookiecutter.project_name }}.Tests/{{ cookiecutter.project_name }}.Tests.csproj +``` + +## Cleanup + +To delete the sample application and the bucket that you created, use the AWS CLI. + +```bash +{{cookiecutter.project_name}}$ sam delete --stack-name sam-app +``` + +## Resources + +For an introduction to the AWS SAM specification, the AWS SAM CLI, and serverless application concepts, see the [AWS SAM Developer Guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html). + +Next, you can use the AWS Serverless Application Repository to deploy ready-to-use apps that go beyond Hello World samples and learn how authors developed their applications. For more information, see the [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) and the [AWS Serverless Application Repository Developer Guide](https://docs.aws.amazon.com/serverlessrepo/latest/devguide/what-is-serverlessrepo.html). diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/events/event-sqs.json b/dotnet10/sqs/{{cookiecutter.project_name}}/events/event-sqs.json new file mode 100644 index 000000000..f697abde1 --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/events/event-sqs.json @@ -0,0 +1,20 @@ +{ + "Records": [ + { + "messageId": "19dd0b57-b21e-4ac1-bd88-01bbb068cb78", + "receiptHandle": "MessageReceiptHandle", + "body": "Hello from SQS!", + "attributes": { + "ApproximateReceiveCount": "1", + "SentTimestamp": "1523232000000", + "SenderId": "123456789012", + "ApproximateFirstReceiveTimestamp": "1523232000001" + }, + "messageAttributes": {}, + "md5OfBody": "7b270e59b47ff90a553787216d55d91d", + "eventSource": "aws:sqs", + "eventSourceARN": "arn:aws:sqs:us-east-1:123456789012:MyQueue", + "awsRegion": "us-east-1" + } + ] +} diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/sqs/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/Function.cs b/dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/Function.cs new file mode 100644 index 000000000..7f8836ae2 --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/Function.cs @@ -0,0 +1,49 @@ +using Amazon.Lambda.Core; +using Amazon.Lambda.SQSEvents; + + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] + +namespace SQSEventSource; + +public class Function +{ + /// + /// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment + /// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the + /// region the Lambda function is executed in. + /// + public Function() + { + + } + + + /// + /// This method is called for every Lambda invocation. This method takes in an SQS event object and can be used + /// to respond to SQS messages. + /// + /// + /// + /// + public async Task FunctionHandler(SQSEvent evnt, ILambdaContext context) + { + foreach(var message in evnt.Records) + { + await ProcessMessageAsync(message, context); + } + + return "done"; + } + + private async Task ProcessMessageAsync(SQSEvent.SQSMessage message, ILambdaContext context) + { + // All log statements are written to CloudWatch by default. For more information, see + // https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-logging.html + context.Logger.LogLine($"Processed message {message.Body}"); + + // TODO: Do interesting work based on the new message + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/SQSEventSource.csproj b/dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/SQSEventSource.csproj new file mode 100644 index 000000000..61f99c75f --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/src/SQSEventSource/SQSEventSource.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + \ No newline at end of file diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/template.yaml b/dotnet10/sqs/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..eb9be19dd --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,56 @@ +# This is the SAM template that represents the architecture of your serverless application +# https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template-basics.html + +# The AWSTemplateFormatVersion identifies the capabilities of the template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/format-version-structure.html +AWSTemplateFormatVersion: 2010-09-09 +Description: >- + {{cookiecutter.project_name}} + +# Transform section specifies one or more macros that AWS CloudFormation uses to process your template +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/transform-section-structure.html +Transform: +- AWS::Serverless-2016-10-31 + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 10 + +# Resources declares the AWS resources that you want to include in the stack +# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resources-section-structure.html +Resources: + # This is an SQS queue with all default configuration properties. To learn more about the available options, see + # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html + SimpleQueue: + Type: AWS::SQS::Queue + + # This is the Lambda function definition associated with the source code: sqs-payload-logger.js. For all available properties, see + # https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + SQSPayloadLogger: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src/SQSEventSource/ + Handler: SQSEventSource::SQSEventSource.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + + MemorySize: 512 + Events: + SQSQueueEvent: + Type: SQS + Properties: + Queue: !GetAtt SimpleQueue.Arn + Policies: + # Give Lambda basic execution Permission to the helloFromLambda + - AWSLambdaBasicExecutionRole + +Outputs: + AppBucketArn: + Description: "SQS Queue ARN" + Value: !GetAtt SimpleQueue.Arn \ No newline at end of file diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/FunctionTest.cs b/dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/FunctionTest.cs new file mode 100644 index 000000000..1230f3b4c --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/FunctionTest.cs @@ -0,0 +1,36 @@ +using Xunit; +using Amazon.Lambda.TestUtilities; +using Amazon.Lambda.SQSEvents; + +using SQSEventSource; + +namespace SQSEventSource.Tests; + +public class FunctionTest +{ + [Fact] + public async Task TestSQSEventLambdaFunction() + { + var sqsEvent = new SQSEvent + { + Records = new List + { + new SQSEvent.SQSMessage + { + Body = "foobar" + } + } + }; + + var logger = new TestLambdaLogger(); + var context = new TestLambdaContext + { + Logger = logger + }; + + var function = new Function(); + await function.FunctionHandler(sqsEvent, context); + + Assert.Contains("Processed message foobar", logger.Buffer.ToString()); + } +} \ No newline at end of file diff --git a/dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/SQSEventSource.Tests.csproj b/dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/SQSEventSource.Tests.csproj new file mode 100644 index 000000000..a43fc5429 --- /dev/null +++ b/dotnet10/sqs/{{cookiecutter.project_name}}/test/SQSEventSource.Tests/SQSEventSource.Tests.csproj @@ -0,0 +1,18 @@ + + + net10.0 + enable + enable + + + + + + + + + + + + + \ No newline at end of file diff --git a/dotnet10/step-func/.gitignore b/dotnet10/step-func/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/step-func/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/step-func/Pipfile b/dotnet10/step-func/Pipfile new file mode 100644 index 000000000..a22660daa --- /dev/null +++ b/dotnet10/step-func/Pipfile @@ -0,0 +1,13 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + +[packages] + +[dev-packages] + +cookiecutter = "*" +pytest-cookies = "*" +pytest = "*" diff --git a/dotnet10/step-func/README.md b/dotnet10/step-func/README.md new file mode 100644 index 000000000..8675762b9 --- /dev/null +++ b/dotnet10/step-func/README.md @@ -0,0 +1,17 @@ +# Cookiecutter dotNet Step Functions Sample App (Stock Trader) for SAM based Serverless App + +A cookiecutter template to create a dotNet Step Functions Sample App (Stock Trader) boilerplate using [Serverless Application Model (SAM)](https://github.com/awslabs/serverless-application-model). + +This application creates a stock trading workflow which runs on a pre-defined schedule. It demonstrates the power of Step Functions to orchestrate Lambda functions and other AWS resources to form complex and robust workflows, coupled with event-driven development using Amazon EventBridge. + +## Requirements + +* [AWS SAM CLI](https://github.com/awslabs/aws-sam-cli) + +## Usage + +Access this template by running `sam init` and choosing it from the list of available templates. + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) \ No newline at end of file diff --git a/dotnet10/step-func/cookiecutter.json b/dotnet10/step-func/cookiecutter.json new file mode 100644 index 000000000..590d62b57 --- /dev/null +++ b/dotnet10/step-func/cookiecutter.json @@ -0,0 +1,13 @@ +{ + "project_name": "Name of the project", + "runtime": "dotnet10", + "architectures": { + "value": [ + "x86_64", "arm64" + ] + }, + "_copy_without_render": [ + ".gitignore" + ] + +} diff --git a/dotnet10/step-func/setup.cfg b/dotnet10/step-func/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/step-func/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/step-func/tests/test_cookiecutter.py b/dotnet10/step-func/tests/test_cookiecutter.py new file mode 100644 index 000000000..2647919cd --- /dev/null +++ b/dotnet10/step-func/tests/test_cookiecutter.py @@ -0,0 +1,54 @@ +""" + Tests cookiecutter baking process and rendered content +""" + + +def test_project_tree(cookies): + result = cookies.bake(extra_context={ + 'project_name': 'hello sam' + }) + assert result.exit_code == 0 + assert result.exception is None + assert result.project.basename == 'hello sam' + assert result.project.isdir() + assert result.project.join('.gitignore').isfile() + assert result.project.join('template.yaml').isfile() + assert result.project.join('README.md').isfile() + + assert result.project.join('statemachine').isdir() + assert result.project.join( + 'statemachine', 'stockTrader.asl.json').isfile() + + assert result.project.join('functions').isdir() + assert result.project.join('functions', 'StockBuyer').isdir() + assert result.project.join( + 'functions', 'StockBuyer', 'StockBuyer.csproj').isfile() + assert result.project.join('functions', 'StockBuyer', 'Function.cs').isfile() + assert result.project.join( + 'functions', 'StockBuyer', 'aws-lambda-tools-defaults.json').isfile() + assert result.project.join('functions', 'StockChecker').isdir() + assert result.project.join( + 'functions', 'StockChecker', 'StockChecker.csproj').isfile() + assert result.project.join('functions', 'StockChecker', 'Function.cs').isfile() + assert result.project.join( + 'functions', 'StockChecker', 'aws-lambda-tools-defaults.json').isfile() + assert result.project.join('functions', 'StockSeller').isdir() + assert result.project.join( + 'functions', 'StockSeller', 'StockSeller.csproj').isfile() + assert result.project.join('functions', 'StockSeller', 'Function.cs').isfile() + assert result.project.join( + 'functions', 'StockSeller', 'aws-lambda-tools-defaults.json').isfile() + + assert result.project.join('test').isdir() + assert result.project.join( + 'test', 'StockBuyer.Test', 'FunctionTest.cs').isfile() + assert result.project.join( + 'test', 'StockBuyer.Test', 'StockBuyer.Tests.csproj').isfile() + assert result.project.join( + 'test', 'StockChecker.Test', 'FunctionTest.cs').isfile() + assert result.project.join( + 'test', 'StockChecker.Test', 'StockChecker.Tests.csproj').isfile() + assert result.project.join( + 'test', 'StockSeller.Test', 'FunctionTest.cs').isfile() + assert result.project.join( + 'test', 'StockSeller.Test', 'StockSeller.Tests.csproj').isfile() diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/.gitignore b/dotnet10/step-func/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/README.md b/dotnet10/step-func/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..ed90346a5 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,104 @@ +# {{ cookiecutter.project_name }} + +This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders: + +- functions - Code for the application's Lambda functions to check the value of, buy, or sell shares of a stock. +- statemachines - Definition for the state machine that orchestrates the stock trading workflow. +- tests - Unit tests for the Lambda functions' application code. +- template.yaml - A template that defines the application's AWS resources. + +This application creates a stock trading workflow which runs on a pre-defined schedule (note that the schedule is disabled by default to avoid incurring charges). It demonstrates the power of Step Functions to orchestrate Lambda functions and other AWS resources to form complex and robust workflows, coupled with event-driven development using Amazon EventBridge. + +AWS Step Functions lets you coordinate multiple AWS services into serverless workflows so you can build and update apps quickly. Using Step Functions, you can design and run workflows that stitch together services, such as AWS Lambda, AWS Fargate, and Amazon SageMaker, into feature-rich applications. + +The application uses several AWS resources, including Step Functions state machines, Lambda functions and an EventBridge rule trigger. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test the Lambda functions within your application, you can use the AWS Toolkit. The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started: + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +The AWS Toolkit for VS Code includes full support for state machine visualization, enabling you to visualize your state machine in real time as you build. The AWS Toolkit for VS Code includes a language server for Amazon States Language, which lints your state machine definition to highlight common errors, provides auto-complete support, and code snippets for each state, enabling you to build state machines faster. + +## Deploy the sample application + +The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. + +To use the SAM CLI, you need the following tools: + +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +You can find your API Gateway Endpoint URL in the output values displayed after deployment. + +## Use the SAM CLI to build and test locally + +Build the Lambda functions in your application with the `sam build` command. + +```bash +{{ cookiecutter.project_name }}$ sam build +``` + +The SAM CLI installs dependencies defined in `functions/FunctionName.csproj`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +## Add a resource to your application +The application template uses AWS Serverless Application Model (AWS SAM) to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources such as functions, triggers, and APIs. For resources not included in [the SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use standard [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html) resource types. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. + +```bash +{{ cookiecutter.project_name }}$ sam logs -n StockCheckerFunction --stack-name {{ cookiecutter.project_name }} --tail +``` + +You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests for the Lambda functions are defined in the `tests` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test tests/StockChecker.Test +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. + +Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/Function.cs b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/Function.cs new file mode 100644 index 000000000..d112b2e38 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/Function.cs @@ -0,0 +1,57 @@ +using Amazon.Lambda.Core; +using System; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.CamelCaseLambdaJsonSerializer))] + +namespace StockBuyer; + +public class StockEvent +{ + public int StockPrice { get; set; } +} + +public class TransactionResult +{ + public string Id { get; set; } = string.Empty; + public string Price { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + public string Qty { get; set; } = string.Empty; + public string Timestamp { get; set; } = string.Empty; +} + +public class Function +{ + + private static readonly Random rand = new Random((Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); + + public TransactionResult FunctionHandler(StockEvent stockEvent, ILambdaContext context) + { + // Sample Lambda function which mocks the operation of buying a random number + // of shares for a stock. + + // For demonstration purposes, this Lambda function does not actually perform any + // actual transactions. It simply returns a mocked result. + + // Parameters + // ---------- + // stockEvent: StockEvent, required + // Input event to the Lambda function + + // context: ILambdaContext + // Lambda Context runtime methods and attributes + + // Returns + // ------ + // TransactionResult: Object containing details of the stock buying transaction + + return new TransactionResult + { + Id = rand.Next().ToString(), + Type = "Buy", + Price = stockEvent.StockPrice.ToString(), + Qty = (rand.Next() % 10 + 1).ToString(), + Timestamp = DateTime.Now.ToString("yyyyMMddHHmmssffff") + }; + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/StockBuyer.csproj b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/StockBuyer.csproj new file mode 100644 index 000000000..dc707a4cc --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/StockBuyer.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/aws-lambda-tools-defaults.json b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..ef79abab6 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockBuyer/aws-lambda-tools-defaults.json @@ -0,0 +1,12 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "template": "template.yaml" +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/Function.cs b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/Function.cs new file mode 100644 index 000000000..28948f4ed --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/Function.cs @@ -0,0 +1,41 @@ +using System; +using Amazon.Lambda.Core; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.CamelCaseLambdaJsonSerializer))] + +namespace StockChecker; + +public class StockEvent +{ + public int StockPrice { get; set; } +} + +public class Function +{ + + private static readonly Random rand = new Random((Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); + + public StockEvent FunctionHandler(ILambdaContext context) + { + // Sample Lambda function which mocks the operation of checking the current price + // of a stock. + + // For demonstration purposes this Lambda function simply returns + // a random integer between 0 and 100 as the stock price. + + // Parameters + // ---------- + // context: ILambdaContext + // Lambda Context runtime methods and attributes + + // Returns + // ------ + // StockEvent: Object containing the current price of the stock + + return new StockEvent + { + StockPrice = rand.Next() % 100 + }; + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/StockChecker.csproj b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/StockChecker.csproj new file mode 100644 index 000000000..dc707a4cc --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/StockChecker.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/aws-lambda-tools-defaults.json b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..ef79abab6 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockChecker/aws-lambda-tools-defaults.json @@ -0,0 +1,12 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "template": "template.yaml" +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/Function.cs b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/Function.cs new file mode 100644 index 000000000..9aeecd924 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/Function.cs @@ -0,0 +1,57 @@ +using Amazon.Lambda.Core; +using System; + +// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. +[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.CamelCaseLambdaJsonSerializer))] + +namespace StockSeller; + +public class StockEvent +{ + public int StockPrice; +} + +public class TransactionResult +{ + public string Id { get; set; } = string.Empty; + public string Price { get; set; } = string.Empty; + public string Type { get; set; } = string.Empty; + public string Qty { get; set; } = string.Empty; + public string Timestamp { get; set; } = string.Empty; +} + +public class Function +{ + + private static readonly Random rand = new Random((Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); + + public TransactionResult FunctionHandler(StockEvent stockEvent, ILambdaContext context) + { + // Sample Lambda function which mocks the operation of selling a random number + // of shares for a stock. + + // For demonstration purposes, this Lambda function does not actually perform any + // actual transactions. It simply returns a mocked result. + + // Parameters + // ---------- + // stockEvent: StockEvent, required + // Input event to the Lambda function + + // context: ILambdaContext + // Lambda Context runtime methods and attributes + + // Returns + // ------ + // TransactionResult: Object containing details of the stock selling transaction + + return new TransactionResult + { + Id = rand.Next().ToString(), + Type = "Sell", + Price = stockEvent.StockPrice.ToString(), + Qty = (rand.Next() % 10 + 1).ToString(), + Timestamp = DateTime.Now.ToString("yyyyMMddHHmmssffff") + }; + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/StockSeller.csproj b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/StockSeller.csproj new file mode 100644 index 000000000..dc707a4cc --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/StockSeller.csproj @@ -0,0 +1,19 @@ + + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/aws-lambda-tools-defaults.json b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..ef79abab6 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/functions/StockSeller/aws-lambda-tools-defaults.json @@ -0,0 +1,12 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "template": "template.yaml" +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/step-func/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/statemachine/stockTrader.asl.json b/dotnet10/step-func/{{cookiecutter.project_name}}/statemachine/stockTrader.asl.json new file mode 100644 index 000000000..d13926453 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/statemachine/stockTrader.asl.json @@ -0,0 +1,97 @@ +{ + "Comment": "A state machine that does mock stock trading.", + "StartAt": "Check Stock Value", + "States": { + "Check Stock Value": { + "Type": "Task", + "Resource": "${StockCheckerFunctionArn}", + "Retry": [ + { + "ErrorEquals": [ + "States.TaskFailed" + ], + "IntervalSeconds": 15, + "MaxAttempts": 5, + "BackoffRate": 1.5 + } + ], + "Next": "Buy or Sell?" + }, + "Buy or Sell?": { + "Type": "Choice", + "Choices": [ + { + "Variable": "$.stockPrice", + "NumericLessThanEquals": 50, + "Next": "Buy Stock" + } + ], + "Default": "Sell Stock" + }, + "Sell Stock": { + "Type": "Task", + "Resource": "${StockSellerFunctionArn}", + "Retry": [ + { + "ErrorEquals": [ + "States.TaskFailed" + ], + "IntervalSeconds": 2, + "MaxAttempts": 3, + "BackoffRate": 1 + } + ], + "Next": "Record Transaction" + }, + "Buy Stock": { + "Type": "Task", + "Resource": "${StockBuyerFunctionArn}", + "Retry": [ + { + "ErrorEquals": [ + "States.TaskFailed" + ], + "IntervalSeconds": 2, + "MaxAttempts": 3, + "BackoffRate": 1 + } + ], + "Next": "Record Transaction" + }, + "Record Transaction": { + "Type": "Task", + "Resource": "${DDBPutItem}", + "Parameters": { + "TableName": "${DDBTable}", + "Item": { + "Id": { + "S.$": "$.id" + }, + "Type": { + "S.$": "$.type" + }, + "Price": { + "N.$": "$.price" + }, + "Quantity": { + "N.$": "$.qty" + }, + "Timestamp": { + "S.$": "$.timestamp" + } + } + }, + "Retry": [ + { + "ErrorEquals": [ + "States.TaskFailed" + ], + "IntervalSeconds": 20, + "MaxAttempts": 5, + "BackoffRate": 10 + } + ], + "End": true + } + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/template.yaml b/dotnet10/step-func/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..1753ecc75 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,94 @@ +AWSTemplateFormatVersion: "2010-09-09" +Transform: AWS::Serverless-2016-10-31 +Description: > + {{ cookiecutter.project_name }} + + Sample SAM Template for {{ cookiecutter.project_name }} + +Resources: + StockTradingStateMachine: + Type: AWS::Serverless::StateMachine # More info about State Machine Resource: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-statemachine.html + Properties: + DefinitionUri: statemachine/stockTrader.asl.json + DefinitionSubstitutions: + StockCheckerFunctionArn: !GetAtt StockCheckerFunction.Arn + StockSellerFunctionArn: !GetAtt StockSellerFunction.Arn + StockBuyerFunctionArn: !GetAtt StockBuyerFunction.Arn + DDBPutItem: !Sub arn:${AWS::Partition}:states:::dynamodb:putItem + DDBTable: !Ref TransactionTable + Events: + HourlyTradingSchedule: + Type: Schedule # More info about Schedule Event Source: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-statemachine-schedule.html + Properties: + Description: Schedule to run the stock trading state machine every hour + Enabled: False + Schedule: "rate(1 hour)" + Policies: # Find out more about SAM policy templates: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html + - LambdaInvokePolicy: + FunctionName: !Ref StockCheckerFunction + - LambdaInvokePolicy: + FunctionName: !Ref StockSellerFunction + - LambdaInvokePolicy: + FunctionName: !Ref StockBuyerFunction + - DynamoDBWritePolicy: + TableName: !Ref TransactionTable + + StockCheckerFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html + Properties: + CodeUri: ./functions/StockChecker/ + Handler: StockChecker::StockChecker.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + + StockSellerFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./functions/StockSeller/ + Handler: StockSeller::StockSeller.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + + StockBuyerFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./functions/StockBuyer/ + Handler: StockBuyer::StockBuyer.Function::FunctionHandler + Runtime: dotnet10 + {%- if cookiecutter.architectures.value != [ ]%} + Architectures: + {%- for arch in cookiecutter.architectures.value %} + - {{arch}} + {%- endfor %} + {%- endif %} + + TransactionTable: + Type: AWS::Serverless::SimpleTable # More info about SimpleTable Resource: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-simpletable.html + Properties: + PrimaryKey: + Name: Id + Type: String + ProvisionedThroughput: + ReadCapacityUnits: 1 + WriteCapacityUnits: 1 + +Outputs: + # StockTradingStateMachineHourlyTradingSchedule is an implicit Schedule event rule created out of Events key under Serverless::StateMachine + # Find out more about other implicit resources you can reference within SAM + # https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources.html + StockTradingStateMachineArn: + Description: "Stock Trading State machine ARN" + Value: !Ref StockTradingStateMachine + StockTradingStateMachineRoleArn: + Description: "IAM Role created for Stock Trading State machine based on the specified SAM Policy Templates" + Value: !GetAtt StockTradingStateMachineRole.Arn \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/FunctionTest.cs b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/FunctionTest.cs new file mode 100644 index 000000000..9eedc9d58 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/FunctionTest.cs @@ -0,0 +1,35 @@ +using Amazon.Lambda.TestUtilities; +using Xunit; + +namespace StockBuyer.Tests; + +public class FunctionTest +{ + + [Fact] + public void TestStockBuyerFunctionHandler() + { + var testStockPrice = 34; + var request = new StockEvent { StockPrice = testStockPrice }; + var context = new TestLambdaContext(); + + var function = new Function(); + var response = function.FunctionHandler(request, context); + + Assert.True(response.Id is string); + Assert.Equal(testStockPrice.ToString(), response.Price); + Assert.Equal("Buy", response.Type); + Assert.True(response.Timestamp is string); + int quantity; + if(int.TryParse(response.Qty, out quantity)) + { + Assert.True(quantity >= 1); + Assert.True(quantity <= 10); + } + else + { + Assert.True(false, "Quantity was not a valid number."); + } + + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/StockBuyer.Tests.csproj b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/StockBuyer.Tests.csproj new file mode 100644 index 000000000..a47cad778 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockBuyer.Test/StockBuyer.Tests.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + + + + + + + + + + + + + + diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/FunctionTest.cs b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/FunctionTest.cs new file mode 100644 index 000000000..8c90c41b8 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/FunctionTest.cs @@ -0,0 +1,20 @@ +using Amazon.Lambda.TestUtilities; +using Xunit; + +namespace StockChecker.Tests; + +public class FunctionTest +{ + + [Fact] + public void TestStockCheckerFunctionHandler() + { + var context = new TestLambdaContext(); + + var function = new Function(); + var response = function.FunctionHandler(context); + + Assert.True(response.StockPrice >= 0); + Assert.True(response.StockPrice <= 99); + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/StockChecker.Tests.csproj b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/StockChecker.Tests.csproj new file mode 100644 index 000000000..bfb131497 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockChecker.Test/StockChecker.Tests.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + + + + + + + + + + + + + + diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/FunctionTest.cs b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/FunctionTest.cs new file mode 100644 index 000000000..f8e58cfd0 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/FunctionTest.cs @@ -0,0 +1,36 @@ +using System; +using Amazon.Lambda.TestUtilities; +using Xunit; + +namespace StockSeller.Tests; + +public class FunctionTest +{ + + [Fact] + public void TestStockSellerFunctionHandler() + { + var testStockPrice = 86; + var request = new StockEvent { StockPrice = testStockPrice }; + var context = new TestLambdaContext(); + + var function = new Function(); + var response = function.FunctionHandler(request, context); + + Assert.True(response.Id is string); + Assert.Equal(testStockPrice.ToString(), response.Price); + Assert.Equal("Sell", response.Type); + Assert.True(response.Timestamp is string); + int quantity; + if(int.TryParse(response.Qty, out quantity)) + { + Assert.True(quantity >= 1); + Assert.True(quantity <= 10); + } + else + { + Assert.True(false, "Quantity was not a valid number."); + } + + } +} \ No newline at end of file diff --git a/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/StockSeller.Tests.csproj b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/StockSeller.Tests.csproj new file mode 100644 index 000000000..52438cbd8 --- /dev/null +++ b/dotnet10/step-func/{{cookiecutter.project_name}}/tests/StockSeller.Test/StockSeller.Tests.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + + + + + + + + + + + + + + diff --git a/dotnet10/web/.gitignore b/dotnet10/web/.gitignore new file mode 100644 index 000000000..74ea25e0e --- /dev/null +++ b/dotnet10/web/.gitignore @@ -0,0 +1,168 @@ + +# Created by https://www.gitignore.io/api/osx,linux,python,windows + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +.pytest_cache/ +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule.* + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + + +# End of https://www.gitignore.io/api/osx,linux,python,windows \ No newline at end of file diff --git a/dotnet10/web/README.md b/dotnet10/web/README.md new file mode 100644 index 000000000..d4ba06dd3 --- /dev/null +++ b/dotnet10/web/README.md @@ -0,0 +1,42 @@ +# Cookiecutter SAM for dotNet based Lambda functions + +This is a [Cookiecutter](https://github.com/audreyr/cookiecutter) template to create a Serverless Hello World App based on Serverless Application Model (SAM) and dotnet. + +It is important to note that you should not try to `git clone` this project but use `cookiecutter` CLI instead as ``{{cookiecutter.project_name}}`` will be rendered based on your input and therefore all variables and files will be rendered properly. + +## Requirements + +Install `cookiecutter` command line: + +**Pip users**: + +* `pip install cookiecutter` + +**Homebrew users**: + +* `brew install cookiecutter` + +**Windows or Pipenv users**: + +* `pipenv install cookiecutter` + +**NOTE**: [`Pipenv`](https://github.com/pypa/pipenv) is the new and recommended Python packaging tool that works across multiple platforms and makes Windows a first-class citizen. + +## Usage + +Generate a new SAM based Serverless App: `cookiecutter gh:aws-samples/cookiecutter-aws-sam-hello-dotnet`. + +You'll be prompted a few questions to help this cookiecutter template to scaffold this project and after its completed you should see a new folder at your current path with the name of the project you gave as input. + +**NOTE**: After you understand how cookiecutter works (cookiecutter.json, mainly), you can fork this repo and apply your own mechanisms to accelerate your development process and this can be followed for any programming language and OS. + + +# Credits + +* This project has been generated with [Cookiecutter](https://github.com/audreyr/cookiecutter) + + +License +------- + +This project is licensed under the terms of the [MIT License with no attribution](/LICENSE) diff --git a/dotnet10/web/cookiecutter.json b/dotnet10/web/cookiecutter.json new file mode 100644 index 000000000..67718311a --- /dev/null +++ b/dotnet10/web/cookiecutter.json @@ -0,0 +1,7 @@ +{ + "project_name": "Name of the project", + "_copy_without_render": [ + ".gitignore" + ] + +} diff --git a/dotnet10/web/setup.cfg b/dotnet10/web/setup.cfg new file mode 100644 index 000000000..eee4ab11a --- /dev/null +++ b/dotnet10/web/setup.cfg @@ -0,0 +1,2 @@ +[install] +prefix= \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/.gitignore b/dotnet10/web/{{cookiecutter.project_name}}/.gitignore new file mode 100644 index 000000000..9baa19505 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/.gitignore @@ -0,0 +1,405 @@ + +# Created by https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode + +### DotSettings ### +*.DotSettings +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### SublimeText ### +# cache files for sublime text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# workspace files are user-specific +*.sublime-workspace + +# project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using SublimeText +# *.sublime-project + +# sftp configuration file +sftp-config.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +ehthumbs.db +ehthumbs_vista.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Uncomment the next line to ignore your web deploy settings. +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. +#*.pubxml +*.pubxml.user +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +### VisualStudio Patch ### +# By default, sensitive information, such as encrypted password +# should be stored in the .pubxml.user file. + + +# End of https://www.gitignore.io/api/macos,linux,windows,sublimetext,dotsettings,visualstudio,visualstudiocode \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/README.md b/dotnet10/web/{{cookiecutter.project_name}}/README.md new file mode 100644 index 000000000..fa84ac8c6 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/README.md @@ -0,0 +1,146 @@ +# {{ cookiecutter.project_name }} + +This project contains source code and supporting files for a serverless application that you can deploy with the SAM CLI. It includes the following files and folders. + +- src - Code for the application's Lambda function. +- events - Invocation events that you can use to invoke the function. +- test - Unit tests for the application code. +- template.yaml - A template that defines the application's AWS resources. + +The application uses several AWS resources, including Lambda functions and an API Gateway API. These resources are defined in the `template.yaml` file in this project. You can update the template to add AWS resources through the same deployment process that updates your application code. + +If you prefer to use an integrated development environment (IDE) to build and test your application, you can use the AWS Toolkit. +The AWS Toolkit is an open source plug-in for popular IDEs that uses the SAM CLI to build and deploy serverless applications on AWS. The AWS Toolkit also adds a simplified step-through debugging experience for Lambda function code. See the following links to get started. + +* [CLion](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [GoLand](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [IntelliJ](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [WebStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [Rider](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PhpStorm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [PyCharm](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [RubyMine](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [DataGrip](https://docs.aws.amazon.com/toolkit-for-jetbrains/latest/userguide/welcome.html) +* [VS Code](https://docs.aws.amazon.com/toolkit-for-vscode/latest/userguide/welcome.html) +* [Visual Studio](https://docs.aws.amazon.com/toolkit-for-visual-studio/latest/user-guide/welcome.html) + +## Deploy the sample application + +The Serverless Application Model Command Line Interface (SAM CLI) is an extension of the AWS CLI that adds functionality for building and testing Lambda applications. It uses Docker to run your functions in an Amazon Linux environment that matches Lambda. It can also emulate your application's build environment and API. + +To use the SAM CLI, you need the following tools. + +* SAM CLI - [Install the SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) +* .NET Core - [Install .NET Core](https://www.microsoft.com/net/download) +* Docker - [Install Docker community edition](https://hub.docker.com/search/?type=edition&offering=community) + +To build and deploy your application for the first time, run the following in your shell: + +```bash +sam build +sam deploy --guided +``` + +The first command will build the source of your application. The second command will package and deploy your application to AWS, with a series of prompts: + +* **Stack Name**: The name of the stack to deploy to CloudFormation. This should be unique to your account and region, and a good starting point would be something matching your project name. +* **AWS Region**: The AWS region you want to deploy your app to. +* **Parameter AppBucketName**: This template includes a parameter to name the S3 bucket you will create as a part of the new application. This name needs to be globally unique. +* **Confirm changes before deploy**: If set to yes, any change sets will be shown to you before execution for manual review. If set to no, the AWS SAM CLI will automatically deploy application changes. +* **Allow SAM CLI IAM role creation**: Many AWS SAM templates, including this example, create AWS IAM roles required for the AWS Lambda function(s) included to access AWS services. By default, these are scoped down to minimum required permissions. To deploy an AWS CloudFormation stack which creates or modifies IAM roles, the `CAPABILITY_IAM` value for `capabilities` must be provided. If permission isn't provided through this prompt, to deploy this example you must explicitly pass `--capabilities CAPABILITY_IAM` to the `sam deploy` command. +* **Save arguments to samconfig.toml**: If set to yes, your choices will be saved to a configuration file inside the project, so that in the future you can just re-run `sam deploy` without parameters to deploy changes to your application. + +## Use the SAM CLI to build and test locally + +Build your application with the `sam build` command. + +```bash +{{ cookiecutter.project_name }}$ sam build +``` + +The SAM CLI installs dependencies defined in `src/ServerlessAPI/ServerlessAPI.csproj`, creates a deployment package, and saves it in the `.aws-sam/build` folder. + +Test a single function by invoking it directly with a test event. An event is a JSON document that represents the input that the function receives from the event source. Test events are included in the `events` folder in this project. + +Run functions locally and invoke them with the `sam local invoke` command. + +```bash +{{ cookiecutter.project_name }}$ sam local invoke NetCodeWebAPIServerless --event events/event.json +``` + +The AWS SAM CLI can also emulate your application's API. Use the `sam local start-api` command to run the API locally on port 3000. + +```bash +{{ cookiecutter.project_name }}$ sam local start-api +{{ cookiecutter.project_name }}$ curl http://localhost:3000/ +``` + +## Add a resource to your application + +The application template uses AWS SAM to define application resources. AWS SAM is an extension of AWS CloudFormation with a simpler syntax for configuring common serverless application resources, such as functions, triggers, and APIs. For resources that aren't included in the [AWS SAM specification](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md), you can use the standard [AWS CloudFormation resource types](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html). + +Update `template.yaml` to add a dead-letter queue to your application. In the **Resources** section, add a resource named **MyQueue** with the type **AWS::SQS::Queue**. Then add a property to the **AWS::Serverless::Function** resource named **DeadLetterQueue** that targets the queue's Amazon Resource Name (ARN), and a policy that grants the function permission to access the queue. + +```yaml +Resources: + MyQueue: + Type: AWS::SQS::Queue + NetCodeWebAPIServerless: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src/ServerlessAPI/ + Handler: ServerlessAPI::ServerlessAPI.Function::FunctionHandler + Runtime: dotnet10 + MemorySize: 1042 + DeadLetterQueue: + Type: SQS + TargetArn: !GetAtt MyQueue.Arn + Policies: + - SQSSendMessagePolicy: + QueueName: !GetAtt MyQueue.QueueName +``` + +The dead-letter queue is a location for Lambda to send events that could not be processed. It's only used if you invoke your function asynchronously, but it's useful here to show how you can modify your application's resources and function configuration. + +Deploy the updated application. + +```bash +{{cookiecutter.project_name}}$ sam build +{{cookiecutter.project_name}}$ sam deploy +``` + +Open the [**Applications**](https://console.aws.amazon.com/lambda/home#/applications) page of the Lambda console, and choose your application. When the deployment completes, view the application resources on the **Overview** tab to see the new resource. Then, choose the function to see the updated configuration that specifies the dead-letter queue. + +## Fetch, tail, and filter Lambda function logs + +To simplify troubleshooting, SAM CLI has a command called `sam logs`. `sam logs` lets you fetch logs generated by your deployed Lambda function from the command line. In addition to printing the logs on the terminal, this command has several nifty features to help you quickly find the bug. + +`NOTE`: This command works for all AWS Lambda functions; not just the ones you deploy using SAM. + +```bash +{{ cookiecutter.project_name }}$ sam logs -n NetCodeWebAPIServerless --stack-name {{ cookiecutter.project_name }} --tail +``` + +You can find more information and examples about filtering Lambda function logs in the [SAM CLI Documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-logging.html). + +## Unit tests + +Tests are defined in the `test` folder in this project. + +```bash +{{ cookiecutter.project_name }}$ dotnet test test/ServerlessAPI.Tests/ServerlessAPI.Tests.csproj +``` + +## Cleanup + +To delete the sample application that you created, use the AWS CLI. Assuming you used your project name for the stack name, you can run the following: + +```bash +sam delete --stack-name {{ cookiecutter.project_name }} +``` + +## Resources + +See the [AWS SAM developer guide](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html) for an introduction to SAM specification, the SAM CLI, and serverless application concepts. + +Next, you can use AWS Serverless Application Repository to deploy ready to use Apps that go beyond hello world samples and learn how authors developed their applications: [AWS Serverless Application Repository main page](https://aws.amazon.com/serverless/serverlessrepo/) diff --git a/dotnet10/web/{{cookiecutter.project_name}}/ServerlessAPI.sln b/dotnet10/web/{{cookiecutter.project_name}}/ServerlessAPI.sln new file mode 100644 index 000000000..42f4fe022 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/ServerlessAPI.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DEAF7F92-411E-4FE7-823B-C4F5DB41BBF8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerlessAPI", "src\ServerlessAPI\ServerlessAPI.csproj", "{FC5B185F-DEBF-46D8-B864-9EF757827789}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{5527D965-E863-4E48-8EC1-713E276D1BBD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerlessAPI.Tests", "tests\ServerlessAPI.Tests\ServerlessAPI.Tests.csproj", "{923A8DB8-35F2-4671-8BC2-A7BB8B639348}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FC5B185F-DEBF-46D8-B864-9EF757827789}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC5B185F-DEBF-46D8-B864-9EF757827789}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC5B185F-DEBF-46D8-B864-9EF757827789}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC5B185F-DEBF-46D8-B864-9EF757827789}.Release|Any CPU.Build.0 = Release|Any CPU + {923A8DB8-35F2-4671-8BC2-A7BB8B639348}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {923A8DB8-35F2-4671-8BC2-A7BB8B639348}.Debug|Any CPU.Build.0 = Debug|Any CPU + {923A8DB8-35F2-4671-8BC2-A7BB8B639348}.Release|Any CPU.ActiveCfg = Release|Any CPU + {923A8DB8-35F2-4671-8BC2-A7BB8B639348}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {FC5B185F-DEBF-46D8-B864-9EF757827789} = {DEAF7F92-411E-4FE7-823B-C4F5DB41BBF8} + {923A8DB8-35F2-4671-8BC2-A7BB8B639348} = {5527D965-E863-4E48-8EC1-713E276D1BBD} + EndGlobalSection +EndGlobal diff --git a/dotnet10/web/{{cookiecutter.project_name}}/omnisharp.json b/dotnet10/web/{{cookiecutter.project_name}}/omnisharp.json new file mode 100644 index 000000000..c0de5e289 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/omnisharp.json @@ -0,0 +1,8 @@ +{ + "fileOptions": { + "excludeSearchPatterns": [ + "**/bin/**/*", + "**/obj/**/*" + ] + } +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Controllers/BooksController.cs b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Controllers/BooksController.cs new file mode 100644 index 000000000..97abc5d8e --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Controllers/BooksController.cs @@ -0,0 +1,104 @@ +using Amazon.DynamoDBv2.DataModel; +using Microsoft.AspNetCore.Mvc; +using ServerlessAPI.Entities; +using ServerlessAPI.Repositories; + +namespace ServerlessAPI.Controllers; + +[Route("api/[controller]")] +[Produces("application/json")] +public class BooksController : ControllerBase +{ + private readonly ILogger logger; + private readonly IBookRepository bookRepository; + + public BooksController(ILogger logger, IBookRepository bookRepository) + { + this.logger = logger; + this.bookRepository = bookRepository; + } + + // GET api/books + [HttpGet] + public async Task>> Get([FromQuery] int limit = 10) + { + if (limit <= 0 || limit > 100) return BadRequest("The limit should been between [1-100]"); + + return Ok(await bookRepository.GetBooksAsync(limit)); + } + + // GET api/books/5 + [HttpGet("{id}")] + public async Task> Get(Guid id) + { + var result = await bookRepository.GetByIdAsync(id); + + if (result == null) + { + return NotFound(); + } + + return Ok(result); + } + + // POST api/books + [HttpPost] + public async Task> Post([FromBody] Book book) + { + if (book == null) return ValidationProblem("Invalid input! Book not informed"); + + var result = await bookRepository.CreateAsync(book); + + if (result) + { + return CreatedAtAction( + nameof(Get), + new { id = book.Id }, + book); + } + else + { + return BadRequest("Fail to persist"); + } + + } + + // PUT api/books/5 + [HttpPut("{id}")] + public async Task Put(Guid id, [FromBody] Book book) + { + if (id == Guid.Empty || book == null) return ValidationProblem("Invalid request payload"); + + // Retrieve the book. + var bookRetrieved = await bookRepository.GetByIdAsync(id); + + if (bookRetrieved == null) + { + var errorMsg = $"Invalid input! No book found with id:{id}"; + return NotFound(errorMsg); + } + + book.Id = bookRetrieved.Id; + + await bookRepository.UpdateAsync(book); + return Ok(); + } + + // DELETE api/books/5 + [HttpDelete("{id}")] + public async Task Delete(Guid id) + { + if (id == Guid.Empty) return ValidationProblem("Invalid request payload"); + + var bookRetrieved = await bookRepository.GetByIdAsync(id); + + if (bookRetrieved == null) + { + var errorMsg = $"Invalid input! No book found with id:{id}"; + return NotFound(errorMsg); + } + + await bookRepository.DeleteAsync(bookRetrieved); + return Ok(); + } +} diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Entities/Book.cs b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Entities/Book.cs new file mode 100644 index 000000000..8ed36d388 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Entities/Book.cs @@ -0,0 +1,30 @@ +using Amazon.DynamoDBv2.DataModel; + +namespace ServerlessAPI.Entities; + +// +/// Map the Book Class to DynamoDb Table +/// To learn more visit https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DeclarativeTagsList.html +/// +[DynamoDBTable("{{cookiecutter.project_name}}BookCatalog")] +public class Book +{ + /// + /// Map c# types to DynamoDb Columns + /// to learn more visit https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/MidLevelAPILimitations.SupportedTypes.html + /// + [DynamoDBHashKey] //Partition key + public Guid Id { get; set; } = Guid.Empty; + + [DynamoDBProperty] + public string Title { get; set; } = string.Empty; + + [DynamoDBProperty] + public string? ISBN { get; set; } + + [DynamoDBProperty] //String Set datatype + public List? Authors { get; set; } + + [DynamoDBIgnore] + public string? CoverPage { get; set; } +} diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Program.cs b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Program.cs new file mode 100644 index 000000000..06c833135 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Program.cs @@ -0,0 +1,42 @@ +using System.Text.Json; +using Amazon; +using Amazon.DynamoDBv2; +using Amazon.DynamoDBv2.DataModel; +using ServerlessAPI.Repositories; + + +var builder = WebApplication.CreateBuilder(args); + +//Logger +builder.Logging + .ClearProviders() + .AddJsonConsole(); + +// Add services to the container. +builder.Services + .AddControllers() + .AddJsonOptions(options => + { + options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); + +string region = Environment.GetEnvironmentVariable("AWS_REGION") ?? RegionEndpoint.USEast2.SystemName; +builder.Services + .AddSingleton(new AmazonDynamoDBClient(RegionEndpoint.GetBySystemName(region))) + .AddScoped() + .AddScoped(); + +// Add AWS Lambda support. When running the application as an AWS Serverless application, Kestrel is replaced +// with a Lambda function contained in the Amazon.Lambda.AspNetCoreServer package, which marshals the request into the ASP.NET Core hosting framework. +builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi); + + +var app = builder.Build(); + +app.UseHttpsRedirection(); +app.UseAuthorization(); +app.MapControllers(); + +app.MapGet("/", () => "Welcome to running ASP.NET Core Minimal API on AWS Lambda"); + +app.Run(); diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Readme.md b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Readme.md new file mode 100644 index 000000000..719c42c1f --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Readme.md @@ -0,0 +1,50 @@ +# ASP.NET Core Minimal API Serverless Application + +This project shows how to run an ASP.NET Core Web API project as an AWS Lambda exposed through Amazon API Gateway. The NuGet package [Amazon.Lambda.AspNetCoreServer](https://www.nuget.org/packages/Amazon.Lambda.AspNetCoreServer) contains a Lambda function that is used to translate requests from API Gateway into the ASP.NET Core framework and then the responses from ASP.NET Core back to API Gateway. + + +For more information about how the Amazon.Lambda.AspNetCoreServer package works and how to extend its behavior view its [README](https://github.com/aws/aws-lambda-dotnet/blob/master/Libraries/src/Amazon.Lambda.AspNetCoreServer/README.md) file in GitHub. + +## Executable Assembly ## + +.NET Lambda projects that use C# top level statements like this project must be deployed as an executable assembly instead of a class library. To indicate to Lambda that the .NET function is an executable assembly the +Lambda function handler value is set to the .NET Assembly name. This is different then deploying as a class library where the function handler string includes the assembly, type and method name. + +To deploy as an executable assembly the Lambda runtime client must be started to listen for incoming events to process. For an ASP.NET Core application the Lambda runtime client is started by included the +`Amazon.Lambda.AspNetCoreServer.Hosting` NuGet package and calling `AddAWSLambdaHosting(LambdaEventSource.HttpApi)` passing in the event source while configuring the services of the application. The +event source can be API Gateway REST API and HTTP API or Application Load Balancer. + +### Project Files ### + +* aws-lambda-tools-defaults.json - default argument settings for use with Visual Studio and command line deployment tools for AWS +* Program.cs - entry point to the application that contains all of the top level statements initializing the ASP.NET Core application. +The call to `AddAWSLambdaHosting` configures the application to work in Lambda when it detects Lambda is the executing environment. +* Controllers\CalculatorController - example Web API controller + +You may also have a test project depending on the options selected. + +## Here are some steps to follow from Visual Studio: + +To deploy your Serverless application, right click the project in Solution Explorer and select *Publish to AWS Lambda*. + +To view your deployed application open the Stack View window by double-clicking the stack name shown beneath the AWS CloudFormation node in the AWS Explorer tree. The Stack View also displays the root URL to your published application. + +## Here are some steps to follow to get started from the command line: + +Once you have edited your template and code you can deploy your application using the [Amazon.Lambda.Tools Global Tool](https://github.com/aws/aws-extensions-for-dotnet-cli#aws-lambda-amazonlambdatools) from the command line. + +Install Amazon.Lambda.Tools Global Tools if not already installed. +``` + dotnet tool install -g Amazon.Lambda.Tools +``` + +If already installed check if new version is available. +``` + dotnet tool update -g Amazon.Lambda.Tools +``` + +Deploy application +``` + cd "{{cookiecutter.project_name}}/src/ServerlessAPI" + sam deploy +``` diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/BookRepository.cs b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/BookRepository.cs new file mode 100644 index 000000000..d6c5717c5 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/BookRepository.cs @@ -0,0 +1,126 @@ +using Amazon.DynamoDBv2.DataModel; +using Amazon.DynamoDBv2.DocumentModel; +using ServerlessAPI.Entities; + +namespace ServerlessAPI.Repositories; + +public class BookRepository : IBookRepository +{ + private readonly IDynamoDBContext context; + private readonly ILogger logger; + + public BookRepository(IDynamoDBContext context, ILogger logger) + { + this.context = context; + this.logger = logger; + } + + public async Task CreateAsync(Book book) + { + try + { + book.Id = Guid.NewGuid(); + await context.SaveAsync(book); + logger.LogInformation("Book {} is added", book.Id); + } + catch (Exception ex) + { + logger.LogError(ex, "fail to persist to DynamoDb Table"); + return false; + } + + return true; + } + + public async Task DeleteAsync(Book book) + { + bool result; + try + { + // Delete the book. + await context.DeleteAsync(book.Id); + // Try to retrieve deleted book. It should return null. + Book deletedBook = await context.LoadAsync(book.Id, new DynamoDBContextConfig + { + ConsistentRead = true + }); + + result = deletedBook == null; + } + catch (Exception ex) + { + logger.LogError(ex, "fail to delete book from DynamoDb Table"); + result = false; + } + + if (result) logger.LogInformation("Book {Id} is deleted", book); + + return result; + } + + public async Task UpdateAsync(Book book) + { + if (book == null) return false; + + try + { + await context.SaveAsync(book); + logger.LogInformation("Book {Id} is updated", book); + } + catch (Exception ex) + { + logger.LogError(ex, "fail to update book from DynamoDb Table"); + return false; + } + + return true; + } + + public async Task GetByIdAsync(Guid id) + { + try + { + return await context.LoadAsync(id); + } + catch (Exception ex) + { + logger.LogError(ex, "fail to update book from DynamoDb Table"); + return null; + } + } + + public async Task> GetBooksAsync(int limit = 10) + { + var result = new List(); + + try + { + if (limit <= 0) + { + return result; + } + + var filter = new ScanFilter(); + filter.AddCondition("Id", ScanOperator.IsNotNull); + var scanConfig = new ScanOperationConfig() + { + Limit = limit, + Filter = filter + }; + var queryResult = context.FromScanAsync(scanConfig); + + do + { + result.AddRange(await queryResult.GetNextSetAsync()); + } + while (!queryResult.IsDone && result.Count < limit); + } + catch (Exception ex) + { + logger.LogError(ex, "fail to list books from DynamoDb Table"); + return new List(); + } + + return result; + } +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/IBookRepository.cs b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/IBookRepository.cs new file mode 100644 index 000000000..1368cfdf6 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/Repositories/IBookRepository.cs @@ -0,0 +1,44 @@ +using ServerlessAPI.Entities; + +namespace ServerlessAPI.Repositories; + +/// +/// Sample DynamoDB Table book CRUD +/// +public interface IBookRepository +{ + /// + /// Include new book to the DynamoDB Table + /// + /// book to include + /// success/failure + Task CreateAsync(Book book); + + /// + /// Remove existing book from DynamoDB Table + /// + /// book to remove + /// + Task DeleteAsync(Book book); + + /// + /// List book from DynamoDb Table with items limit (default=10) + /// + /// limit (default=10) + /// Collection of books + Task> GetBooksAsync(int limit = 10); + + /// + /// Get book by PK + /// + /// book`s PK + /// Book object + Task GetByIdAsync(Guid id); + + /// + /// Update book content + /// + /// book to be updated + /// + Task UpdateAsync(Book book); +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/ServerlessAPI.csproj b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/ServerlessAPI.csproj new file mode 100644 index 000000000..6f89a1dd7 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/ServerlessAPI.csproj @@ -0,0 +1,24 @@ + + + + net10.0 + enable + enable + true + Lambda + + true + + true + + + + + + + + + + + + diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.Development.json b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.Development.json new file mode 100644 index 000000000..5e9fd7fbf --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.json b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.json new file mode 100644 index 000000000..149cb0912 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/aws-lambda-tools-defaults.json b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/aws-lambda-tools-defaults.json new file mode 100644 index 000000000..d75bab928 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/src/ServerlessAPI/aws-lambda-tools-defaults.json @@ -0,0 +1,14 @@ +{ + "Information": [ + "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", + "To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.", + "dotnet lambda help", + "All the command line options for the Lambda command can be specified in this file." + ], + "profile": "", + "region": "", + "configuration": "Release", + "s3-prefix": "{{cookiecutter.project_name}}/", + "template": "serverless.template", + "template-parameters": "" +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/template.yaml b/dotnet10/web/{{cookiecutter.project_name}}/template.yaml new file mode 100644 index 000000000..ff4c2f7c4 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/template.yaml @@ -0,0 +1,56 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Sample SAM Template for {{cookiecutter.project_name}} + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 100 + +Resources: + NetCodeWebAPIServerless: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + Description: A simple example includes a .NET Core WebAPI App with DynamoDB table. + CodeUri: ./src/ServerlessAPI/ + Handler: ServerlessAPI + Runtime: dotnet10 + MemorySize: 1024 + Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object + Variables: + SAMPLE_TABLE: !Ref SampleTable + Policies: + # Give Create/Read/Update/Delete Permissions to the SampleTable + - DynamoDBCrudPolicy: + TableName: !Ref SampleTable + Events: + ProxyResource: + Type: HttpApi + Properties: + PayloadFormatVersion: "2.0" + Path: /{proxy+} + Method: ANY + RootResource: + PayloadFormatVersion: "2.0" + Type: HttpApi + Properties: + Path: / + Method: ANY + + # DynamoDB table to store item: {id: <ID>, name: <NAME>} + SampleTable: + Type: AWS::Serverless::SimpleTable + Properties: + TableName: {{cookiecutter.project_name}}BookCatalog + PrimaryKey: + Name: Id + Type: String + ProvisionedThroughput: + ReadCapacityUnits: 2 + WriteCapacityUnits: 2 + +Outputs: + WebEndpoint: + Description: "API Gateway endpoint URL" + Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.${AWS::URLSuffix}/" diff --git a/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/BookControllerTest.cs b/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/BookControllerTest.cs new file mode 100644 index 000000000..f5091aaf9 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/BookControllerTest.cs @@ -0,0 +1,52 @@ +using ServerlessAPI.Entities; +using ServerlessAPI.Repositories; +using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; +using System.Net.Http.Json; +using System.Threading.Tasks; +using Xunit; + +namespace ServerlessAPI.Tests; + +public class BookControllerTest +{ + private readonly WebApplicationFactory webApplication; + public BookControllerTest() + { + webApplication = new WebApplicationFactory() + .WithWebHostBuilder(builder => + { + builder.ConfigureServices(services => + { + //Mock the repository implementation + //to remove infra dependencies for Test project + services.AddScoped(); + }); + }); + } + + [Theory] + [InlineData(10)] + [InlineData(20)] + public async Task Call_GetApiBooks_ShouldReturn_LimitedListOfBooks(int limit) + { + var client = webApplication.CreateClient(); + var books = await client.GetFromJsonAsync>($"/api/Books?limit={limit}"); + + Assert.NotEmpty(books); + Assert.Equal(limit, books?.Count); + } + + [Theory] + [InlineData(0)] + [InlineData(101)] + public async Task Call_GetApiBook_ShouldReturn_BadRequest(int limit) + { + var client = webApplication.CreateClient(); + var result = await client.GetAsync($"/api/Books?limit={limit}"); + + Assert.Equal(System.Net.HttpStatusCode.BadRequest, result?.StatusCode); + + } +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/MockBookRepository.cs b/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/MockBookRepository.cs new file mode 100644 index 000000000..159550f78 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/MockBookRepository.cs @@ -0,0 +1,52 @@ +using Bogus; +using ServerlessAPI.Entities; +using ServerlessAPI.Repositories; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace ServerlessAPI.Tests; + +internal class MockBookRepository : IBookRepository +{ + private readonly Faker fakeEntity; + + public MockBookRepository() + { + fakeEntity = new Faker() + .RuleFor(o => o.Authors, f => { return new List() { f.Name.FullName(), f.Name.FullName() }; }) + .RuleFor(o => o.CoverPage, f => f.Image.PicsumUrl()) + .RuleFor(o => o.Id, f => Guid.NewGuid()); + } + + public Task CreateAsync(Book book) + { + return Task.FromResult(true); + } + + public Task DeleteAsync(Book book) + { + return Task.FromResult(true); + } + + public Task> GetBooksAsync(int limit = 10) + { + IList books = fakeEntity.Generate(limit).ToList(); + + return Task.FromResult(books); + } + + public Task GetByIdAsync(Guid id) + { + _ = fakeEntity.RuleFor(o => o.Id, f => id); + var book = fakeEntity.Generate() ?? null; + + return Task.FromResult(book); + } + + public Task UpdateAsync(Book book) + { + return Task.FromResult(true); + } +} \ No newline at end of file diff --git a/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/ServerlessAPI.Tests.csproj b/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/ServerlessAPI.Tests.csproj new file mode 100644 index 000000000..ee974d5d1 --- /dev/null +++ b/dotnet10/web/{{cookiecutter.project_name}}/tests/ServerlessAPI.Tests/ServerlessAPI.Tests.csproj @@ -0,0 +1,29 @@ + + + + net10.0 + enable + + false + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + diff --git a/manifest-v2.json b/manifest-v2.json index c59fe8e06..ccd81bcba 100644 --- a/manifest-v2.json +++ b/manifest-v2.json @@ -191,6 +191,88 @@ "useCaseName": "Data processing" } ], + "dotnet10": [ + { + "directory": "dotnet10/sqs", + "displayName": "Quick Start: SQS", + "dependencyManager": "cli-package", + "appTemplate": "quick-start-sqs", + "packageType": "Zip", + "useCaseName": "Data processing" + }, + { + "directory": "dotnet10/sns", + "displayName": "Quick Start: SNS", + "dependencyManager": "cli-package", + "appTemplate": "quickstart-sns", + "packageType": "Zip", + "useCaseName": "Data processing" + }, + { + "directory": "dotnet10/hello", + "displayName": "Hello World Example", + "dependencyManager": "cli-package", + "appTemplate": "hello-world", + "packageType": "Zip", + "useCaseName": "Hello World Example" + }, + { + "directory": "dotnet10/hello-native-aot", + "displayName": "Hello World Example using native AOT", + "dependencyManager": "cli-package", + "appTemplate": "hello-world-native-aot", + "packageType": "Zip", + "useCaseName": "Hello World Example" + }, + { + "directory": "dotnet10/hello-pt", + "displayName": "Hello World Example .NET With Powertools for AWS Lambda", + "dependencyManager": "cli-package", + "appTemplate": "hello-world-powertools-dotnet", + "packageType": "Zip", + "useCaseName": "Hello World Example with Powertools for AWS Lambda" + }, + { + "directory": "dotnet10/step-func", + "displayName": "Step Functions Sample App (Stock Trader)", + "dependencyManager": "cli-package", + "appTemplate": "step-functions-sample-app", + "packageType": "Zip", + "useCaseName": "Multi-step workflow" + }, + { + "directory": "dotnet10/cw-event", + "displayName": "Quick Start: Scheduled Events", + "dependencyManager": "cli-package", + "appTemplate": "quick-start-cloudwatch-events", + "packageType": "Zip", + "useCaseName": "Scheduled task" + }, + { + "directory": "dotnet10/scratch", + "displayName": "Quick Start: From Scratch", + "dependencyManager": "cli-package", + "appTemplate": "quick-start-from-scratch", + "packageType": "Zip", + "useCaseName": "Standalone function" + }, + { + "directory": "dotnet10/web", + "displayName": "Quick Start: Web Backend", + "dependencyManager": "cli-package", + "appTemplate": "quick-start-web", + "packageType": "Zip", + "useCaseName": "Serverless API" + }, + { + "directory": "dotnet10/s3", + "displayName": "Quick Start: S3", + "dependencyManager": "cli-package", + "appTemplate": "quick-start-s3", + "packageType": "Zip", + "useCaseName": "Data processing" + } + ], "go (provided.al2)": [ { "directory": "al2/go/hello", @@ -1858,6 +1940,16 @@ "useCaseName": "Hello World Example" } ], + "amazon/dotnet10-base": [ + { + "directory": "dotnet10/hello-img", + "displayName": "Hello World Lambda Image Example", + "dependencyManager": "cli-package", + "appTemplate": "hello-world-lambda-image", + "packageType": "Image", + "useCaseName": "Hello World Example" + } + ], "amazon/java8.al2-base": [ { "directory": "java8.al2/hello-img-gradle", diff --git a/tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py b/tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py new file mode 100644 index 000000000..aa6734011 --- /dev/null +++ b/tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py @@ -0,0 +1,93 @@ +from tests.integration.build_invoke.build_invoke_base import BuildInvokeBase + +""" +sam build does not support to build dotnetcore 3.1 templates using container, +here we put them in a separate file and use a dedicate codebuild project with .net 3.1 runtime to build them. + +For each template, it will test the following sam commands: +1. sam init +2. sam build --use-container (if self.use_container is False, --use-container will be omitted) +3. (if there are event jsons), for each event json, check `sam local invoke` response is a valid json +""" + + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_hello_dotnet(BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase): + use_container = False + directory = "dotnet10/hello" + should_test_lint = False + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_hello_native_aot_dotnet(BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase): + use_container = False + directory = "dotnet10/hello-native-aot" + should_test_lint = False + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_hello_dotnet_pt(BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase): + use_container = False + directory = "dotnet10/hello-pt" + should_test_lint = False + + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_quick_start_s3_dotnet( + BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase +): + use_container = False + directory = "dotnet10/s3" + should_test_lint = False + + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_quick_start_sns_dotnet( + BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase +): + use_container = False + directory = "dotnet10/sns" + should_test_lint = False + + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_quick_start_sqs_dotnet( + BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase +): + use_container = False + directory = "dotnet10/sqs" + should_test_lint = False + + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_hello_step_functions_sample_app( + BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase +): + use_container = False + directory = "dotnet10/step-func" + should_test_lint = False + + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_quick_start_cloudwatch_events_dotnet( + BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase +): + use_container = False + directory = "dotnet10/cw-event" + should_test_lint = False + + +class BuildInvoke_dotnet10_cookiecutter_aws_from_scratch_dotnet(BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase): + use_container = False + directory = "dotnet10/scratch" + should_test_lint = False + + +class BuildInvoke_dotnet10_cookiecutter_aws_sam_quick_start_web_dotnet( + BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase +): + use_container = False + directory = "dotnet10/web" + should_test_lint = False + + +# +# Image templates +# + + +class BuildInvoke_image_dotnet10_cookiecutter_aws_sam_hello_dotnet_lambda_image( + BuildInvokeBase.DotNetCoreExtraRerunBuildInvokeBase +): + directory = "dotnet10/hello-img" + should_test_lint = False diff --git a/tests/integration/unit_test/test_unit_test_dotnet10.py b/tests/integration/unit_test/test_unit_test_dotnet10.py new file mode 100644 index 000000000..41d378bf8 --- /dev/null +++ b/tests/integration/unit_test/test_unit_test_dotnet10.py @@ -0,0 +1,67 @@ +# dotnet unit tests are executed from test directories, so code_directories point to test directories +from tests.integration.unit_test.unit_test_base import UnitTestBase + + +class UnitTest_dotnet10_cookiecutter_aws_sam_hello_dotnet(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/hello" + code_directories = ["test/HelloWorld.Test"] + should_test_lint = False + +class UnitTest_dotnet10_cookiecutter_aws_sam_hello_native_aot_dotnet(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/hello-native-aot" + code_directories = ["test/HelloWorldAot.Test"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_hello_dotnet(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/hello-img" + code_directories = ["test/HelloWorld.Test"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_hello_dotnet_pt(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/hello-pt" + code_directories = ["test/HelloWorld.Test"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_hello_step_functions_sample_app(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/step-func" + code_directories = ["tests/StockBuyer.Test", "tests/StockChecker.Test", "tests/StockSeller.Test"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_quick_start_s3_dotnet(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/s3" + code_directories = ["test/S3EventSource.Tests"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_cloudwatch_events_dotnet(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/cw-event" + code_directories = ["test/CloudWatchEventSource.Tests"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_quickstart_sns_dotnet_sample_app(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/sns" + code_directories = ["test/SNSEventSource.Tests"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_from_scratch_dotnet(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/scratch" + code_directories = ["test/ScratchLambda.Tests"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_quick_start_web_dotnet(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/web" + code_directories = ["tests/ServerlessAPI.Tests"] + should_test_lint = False + + +class UnitTest_dotnet10_cookiecutter_aws_sam_quick_start_sqs(UnitTestBase.DotNetCoreUnitTestBase): + directory = "dotnet10/sqs" + code_directories = ["test/SQSEventSource.Tests"] + should_test_lint = False From 783a5f8b9d43a0c46ede6f25772a7e2be69d83e5 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 16 Dec 2025 22:01:26 +0000 Subject: [PATCH 2/6] chore: remove the outdated comments --- .../build_invoke/dotnet/test_build_invoke_dotnet10.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py b/tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py index aa6734011..95adadc85 100644 --- a/tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py +++ b/tests/integration/build_invoke/dotnet/test_build_invoke_dotnet10.py @@ -1,9 +1,6 @@ from tests.integration.build_invoke.build_invoke_base import BuildInvokeBase """ -sam build does not support to build dotnetcore 3.1 templates using container, -here we put them in a separate file and use a dedicate codebuild project with .net 3.1 runtime to build them. - For each template, it will test the following sam commands: 1. sam init 2. sam build --use-container (if self.use_container is False, --use-container will be omitted) From 1fb5a5ee00865d4b05320822f7874af4ffea3808 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 16 Dec 2025 22:05:02 +0000 Subject: [PATCH 3/6] chore: use dotnet 10 base images --- .../{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile index b34d90f37..e835b1951 100644 --- a/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile +++ b/dotnet10/hello-img/{{cookiecutter.project_name}}/src/HelloWorld/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build-image +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build-image ARG FUNCTION_DIR="/build" ARG SAM_BUILD_MODE="run" @@ -16,7 +16,7 @@ RUN mkdir -p build_artifacts RUN if [ "$SAM_BUILD_MODE" = "debug" ]; then dotnet lambda package --configuration Debug; else dotnet lambda package --configuration Release; fi RUN if [ "$SAM_BUILD_MODE" = "debug" ]; then cp -r /build/bin/Debug/net10.0/publish/* /build/build_artifacts; else cp -r /build/bin/Release/net10.0/publish/* /build/build_artifacts; fi -FROM public.ecr.aws/lambda/dotnet:8 +FROM public.ecr.aws/lambda/dotnet:10 COPY --from=build-image /build/build_artifacts/ /var/task/ # Command can be overwritten by providing a different command in the template directly. From 922c7854bb52cc81d299f91aa35ebee0a8673d41 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 16 Dec 2025 22:45:25 +0000 Subject: [PATCH 4/6] chore: update maven version --- al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile b/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile index c6589ecff..291d109dc 100644 --- a/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile +++ b/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile @@ -25,7 +25,7 @@ RUN rm -rf $GRAAL_FOLDERNAME # Maven -ENV MVN_VERSION 3.9.11 +ENV MVN_VERSION 3.9.12 ENV MVN_FOLDERNAME apache-maven-${MVN_VERSION} ENV MVN_FILENAME apache-maven-${MVN_VERSION}-bin.tar.gz RUN curl -4 -L https://dlcdn.apache.org/maven/maven-3/${MVN_VERSION}/binaries/${MVN_FILENAME} | tar -xvz From 0cd0e8b4cb756b30c47bd23383a7c66496397175 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 16 Dec 2025 23:19:28 +0000 Subject: [PATCH 5/6] chore: install maven before graal --- .../{{cookiecutter.project_name}}/Dockerfile | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile b/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile index 291d109dc..262260744 100644 --- a/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile +++ b/al2/graalvm/17/maven/{{cookiecutter.project_name}}/Dockerfile @@ -10,6 +10,14 @@ RUN yum -y update \ zlib-devel glibc-static libcxx libcxx-devel llvm-toolset-7 zlib-static \ && rm -rf /var/cache/yum +# Maven +ENV MVN_VERSION 3.9.12 +ENV MVN_FOLDERNAME apache-maven-${MVN_VERSION} +ENV MVN_FILENAME apache-maven-${MVN_VERSION}-bin.tar.gz +RUN curl -4 -L https://dlcdn.apache.org/maven/maven-3/${MVN_VERSION}/binaries/${MVN_FILENAME} | tar -xvz +RUN mv $MVN_FOLDERNAME /usr/lib/maven +RUN rm -rf $MVN_FOLDERNAME + # Graal VM ENV JAVA_VERSION java17 ENV GRAAL_VERSION 22.1.0 @@ -23,15 +31,6 @@ RUN curl -4 -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm RUN mv $GRAAL_FOLDERNAME /usr/lib/graalvm RUN rm -rf $GRAAL_FOLDERNAME - -# Maven -ENV MVN_VERSION 3.9.12 -ENV MVN_FOLDERNAME apache-maven-${MVN_VERSION} -ENV MVN_FILENAME apache-maven-${MVN_VERSION}-bin.tar.gz -RUN curl -4 -L https://dlcdn.apache.org/maven/maven-3/${MVN_VERSION}/binaries/${MVN_FILENAME} | tar -xvz -RUN mv $MVN_FOLDERNAME /usr/lib/maven -RUN rm -rf $MVN_FOLDERNAME - # AWS Lambda Builders RUN cd /tmp \ && wget https://www.python.org/ftp/python/3.9.17/Python-3.9.17.tgz \ From cf88876671a2468527320eefa27f2f0107307724 Mon Sep 17 00:00:00 2001 From: Harold Sun Date: Tue, 16 Dec 2025 23:21:37 +0000 Subject: [PATCH 6/6] chore: update maven version --- al2/graalvm/11/maven/{{cookiecutter.project_name}}/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/al2/graalvm/11/maven/{{cookiecutter.project_name}}/Dockerfile b/al2/graalvm/11/maven/{{cookiecutter.project_name}}/Dockerfile index 060fd68a4..cc0ec353f 100644 --- a/al2/graalvm/11/maven/{{cookiecutter.project_name}}/Dockerfile +++ b/al2/graalvm/11/maven/{{cookiecutter.project_name}}/Dockerfile @@ -24,7 +24,7 @@ RUN mv $GRAAL_FOLDERNAME /usr/lib/graalvm RUN rm -rf $GRAAL_FOLDERNAME # Maven -ENV MVN_VERSION 3.9.11 +ENV MVN_VERSION 3.9.12 ENV MVN_FOLDERNAME apache-maven-${MVN_VERSION} ENV MVN_FILENAME apache-maven-${MVN_VERSION}-bin.tar.gz RUN curl -4 -L https://dlcdn.apache.org/maven/maven-3/${MVN_VERSION}/binaries/${MVN_FILENAME} | tar -xvz