├── LambdaApiSolution ├── src │ ├── LambdaApiSolution │ │ ├── GlobalSuppressions.cs │ │ ├── Program.cs │ │ ├── Constants.cs │ │ ├── SolutionStage.cs │ │ ├── LambdaApiSolution.csproj │ │ ├── LambdaApiSolutionStack.cs │ │ └── PipelineStack.cs │ ├── LambdaApiSolution.DockerFunction │ │ ├── test │ │ │ └── LambdaApiSolution.DockerFunction.Tests │ │ │ │ ├── FunctionTest.cs │ │ │ │ └── LambdaApiSolution.DockerFunction.Tests.csproj │ │ └── src │ │ │ └── LambdaApiSolution.DockerFunction │ │ │ ├── LambdaApiSolution.DockerFunction.csproj │ │ │ ├── aws-lambda-tools-defaults.json │ │ │ ├── Function.cs │ │ │ ├── Dockerfile │ │ │ └── Readme.md │ ├── LambdaApiSolution.sln │ └── .editorconfig ├── cdk.json ├── README.md └── .gitignore ├── LICENSE ├── .gitignore └── README.md /LambdaApiSolution/src/LambdaApiSolution/GlobalSuppressions.cs: -------------------------------------------------------------------------------- 1 | [assembly: 2 | System.Diagnostics.CodeAnalysis.SuppressMessage("Potential Code Quality Issues", 3 | "RECS0026:Possible unassigned object created by 'new'", 4 | Justification = "Constructs add themselves to the scope in which they are created")] -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution/Program.cs: -------------------------------------------------------------------------------- 1 | using Amazon.CDK; 2 | 3 | namespace LambdaApiSolution 4 | { 5 | sealed class Program 6 | { 7 | public static void Main(string[] args) 8 | { 9 | App app = new App(); 10 | PipelineStack pipelineStack = new PipelineStack(app, "LambdaApiSolutionPipelineStack"); 11 | app.Synth(); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace LambdaApiSolution 2 | { 3 | public static class Constants 4 | { 5 | public static string Branch = "main"; 6 | public static string GitHubTokenSecretsManagerId = "GitHub-Token"; 7 | public static string Owner = "scottenriquez"; 8 | public static string RepositoryName = "dotnet-5-lambda-api-cdk"; 9 | } 10 | } -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution/SolutionStage.cs: -------------------------------------------------------------------------------- 1 | using Amazon.CDK; 2 | using Construct = Constructs.Construct; 3 | 4 | namespace LambdaApiSolution 5 | { 6 | public class SolutionStage : Stage 7 | { 8 | public SolutionStage(Construct scope, string id, IStageProps props = null) : base(scope, id, props) 9 | { 10 | LambdaApiSolutionStack lambdaApiSolutionStack = new LambdaApiSolutionStack(this, "Solution"); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /LambdaApiSolution/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "dotnet run -p src/LambdaApiSolution/LambdaApiSolution.csproj", 3 | "context": { 4 | "@aws-cdk/core:enableStackNameDuplicates": "true", 5 | "aws-cdk:enableDiffNoFail": "true", 6 | "@aws-cdk/core:newStyleStackSynthesis": "true", 7 | "@aws-cdk/core:stackRelativeExports": "true", 8 | "@aws-cdk/aws-ecr-assets:dockerIgnoreSupport": true, 9 | "@aws-cdk/aws-secretsmanager:parseOwnedSecretName": true, 10 | "@aws-cdk/aws-kms:defaultKeyPolicies": true, 11 | "@aws-cdk/aws-s3:grantWriteWithoutAcl": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /LambdaApiSolution/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to your CDK C# project! 2 | 3 | This is a blank project for C# development with CDK. 4 | 5 | The `cdk.json` file tells the CDK Toolkit how to execute your app. 6 | 7 | It uses the [.NET Core CLI](https://docs.microsoft.com/dotnet/articles/core/) to compile and execute your project. 8 | 9 | ## Useful commands 10 | 11 | * `dotnet build src` compile this app 12 | * `cdk deploy` deploy this stack to your default AWS account/region 13 | * `cdk diff` compare deployed stack with current state 14 | * `cdk synth` emits the synthesized CloudFormation template -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.DockerFunction/test/LambdaApiSolution.DockerFunction.Tests/FunctionTest.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Lambda.APIGatewayEvents; 2 | using Xunit; 3 | using Amazon.Lambda.TestUtilities; 4 | 5 | namespace LambdaApiSolution.DockerFunction.Tests 6 | { 7 | public class FunctionTest 8 | { 9 | [Fact] 10 | public void TestToUpperFunction() 11 | { 12 | Function function = new Function(); 13 | TestLambdaContext context = new TestLambdaContext(); 14 | APIGatewayProxyRequest apiGatewayProxyRequest = new APIGatewayProxyRequest() 15 | { 16 | Body = "hello world" 17 | }; 18 | Casing casing = function.FunctionHandler(apiGatewayProxyRequest, context); 19 | Assert.Equal("hello world", casing.Lower); 20 | Assert.Equal("HELLO WORLD", casing.Upper); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.DockerFunction/test/LambdaApiSolution.DockerFunction.Tests/LambdaApiSolution.DockerFunction.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net5.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction/LambdaApiSolution.DockerFunction.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net5.0 4 | true 5 | Lambda 6 | 7 | 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction/aws-lambda-tools-defaults.json: -------------------------------------------------------------------------------- 1 | { 2 | "Information": [ 3 | "This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.", 4 | "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.", 5 | "dotnet lambda help", 6 | "All the command line options for the Lambda command can be specified in this file." 7 | ], 8 | "profile": "", 9 | "region": "", 10 | "configuration": "Release", 11 | "package-type": "image", 12 | "function-memory-size": 256, 13 | "function-timeout": 30, 14 | "image-command": "LambdaApiSolution.DockerFunction::LambdaApiSolution.DockerFunction.Function::FunctionHandler", 15 | "docker-host-build-output-dir": "./bin/Release/net5.0/linux-x64/publish" 16 | } -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction/Function.cs: -------------------------------------------------------------------------------- 1 | using Amazon.Lambda.APIGatewayEvents; 2 | using Amazon.Lambda.Core; 3 | 4 | // Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class. 5 | [assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))] 6 | 7 | namespace LambdaApiSolution.DockerFunction 8 | { 9 | public class Function 10 | { 11 | /// 12 | /// A simple function that takes a string and returns both the upper and lower case version of the string. 13 | /// 14 | /// 15 | /// 16 | /// 17 | public Casing FunctionHandler(APIGatewayProxyRequest apiGatewayProxyRequest, ILambdaContext context) 18 | { 19 | string input = apiGatewayProxyRequest.Body; 20 | return new Casing(input.ToLower(), input.ToUpper()); 21 | } 22 | } 23 | 24 | public record Casing(string Lower, string Upper); 25 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Scottie Enriquez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM public.ecr.aws/lambda/dotnet:5.0 2 | FROM mcr.microsoft.com/dotnet/sdk:5.0 as build-image 3 | 4 | ARG FUNCTION_DIR="/build" 5 | ARG CONFIGURATION="release" 6 | ENV PATH="/root/.dotnet/tools:${PATH}" 7 | 8 | RUN apt-get update && apt-get -y install zip 9 | 10 | RUN mkdir $FUNCTION_DIR 11 | WORKDIR $FUNCTION_DIR 12 | COPY Function.cs LambdaApiSolution.DockerFunction.csproj aws-lambda-tools-defaults.json $FUNCTION_DIR/ 13 | RUN dotnet tool install -g Amazon.Lambda.Tools 14 | 15 | RUN mkdir -p build_artifacts 16 | RUN if [ "$CONFIGURATION" = "debug" ]; then dotnet lambda package --configuration Debug --package-type zip; else dotnet lambda package --configuration Release --package-type zip; fi 17 | RUN if [ "$CONFIGURATION" = "debug" ]; then cp -r /build/bin/Debug/net5.0/publish/* /build/build_artifacts; else cp -r /build/bin/Release/net5.0/publish/* /build/build_artifacts; fi 18 | 19 | FROM public.ecr.aws/lambda/dotnet:5.0 20 | 21 | COPY --from=build-image /build/build_artifacts/ /var/task/ 22 | CMD ["LambdaApiSolution.DockerFunction::LambdaApiSolution.DockerFunction.Function::FunctionHandler"] -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution/LambdaApiSolution.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net5.0 6 | 7 | Major 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution/LambdaApiSolutionStack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Amazon.CDK; 3 | using Amazon.CDK.AWS.APIGatewayv2; 4 | using Amazon.CDK.AWS.APIGatewayv2.Integrations; 5 | using Amazon.CDK.AWS.Lambda; 6 | 7 | namespace LambdaApiSolution 8 | { 9 | public class LambdaApiSolutionStack : Stack 10 | { 11 | internal LambdaApiSolutionStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) 12 | { 13 | DockerImageCode dockerImageCode = 14 | DockerImageCode.FromImageAsset("src/LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction"); 15 | DockerImageFunction dockerImageFunction = new DockerImageFunction(this, "LambdaFunction", 16 | new DockerImageFunctionProps() 17 | { 18 | Code = dockerImageCode, 19 | Description = ".NET 5 Docker Lambda function" 20 | }); 21 | HttpApi httpApi = new HttpApi(this, "APIGatewayForLambda", new HttpApiProps() 22 | { 23 | ApiName = "APIGatewayForLambda", 24 | CreateDefaultStage = true, 25 | CorsPreflight = new CorsPreflightOptions() 26 | { 27 | AllowMethods = new[] {HttpMethod.GET}, 28 | AllowOrigins = new[] {"*"}, 29 | MaxAge = Duration.Days(10) 30 | } 31 | }); 32 | LambdaProxyIntegration lambdaProxyIntegration = new LambdaProxyIntegration(new LambdaProxyIntegrationProps() 33 | { 34 | Handler = dockerImageFunction, 35 | PayloadFormatVersion = PayloadFormatVersion.VERSION_2_0 36 | }); 37 | httpApi.AddRoutes(new AddRoutesOptions() 38 | { 39 | Path = "/casing", 40 | Integration = lambdaProxyIntegration, 41 | Methods = new[] {HttpMethod.POST} 42 | }); 43 | string guid = Guid.NewGuid().ToString(); 44 | CfnOutput apiUrl = new CfnOutput(this, "APIGatewayURLOutput", new CfnOutputProps() 45 | { 46 | ExportName = $"APIGatewayEndpointURL-{guid}", 47 | Value = httpApi.ApiEndpoint 48 | }); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution/PipelineStack.cs: -------------------------------------------------------------------------------- 1 | using Amazon.CDK; 2 | using Amazon.CDK.AWS.CodeBuild; 3 | using Amazon.CDK.AWS.CodePipeline; 4 | using Amazon.CDK.AWS.CodePipeline.Actions; 5 | using Amazon.CDK.Pipelines; 6 | 7 | namespace LambdaApiSolution 8 | { 9 | public class PipelineStack : Stack 10 | { 11 | internal PipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) 12 | { 13 | Artifact_ sourceArtifact = new Artifact_(); 14 | Artifact_ cloudAssemblyArtifact = new Artifact_(); 15 | CdkPipeline pipeline = new CdkPipeline(this, "LambdaApiSolutionPipeline", new CdkPipelineProps() 16 | { 17 | CloudAssemblyArtifact = cloudAssemblyArtifact, 18 | PipelineName = "LambdaApiSolutionPipeline", 19 | SourceAction = new GitHubSourceAction(new GitHubSourceActionProps() 20 | { 21 | ActionName = "GitHubSource", 22 | Output = sourceArtifact, 23 | OauthToken = SecretValue.SecretsManager(Constants.GitHubTokenSecretsManagerId), 24 | Owner = Constants.Owner, 25 | Repo = Constants.RepositoryName, 26 | Branch = Constants.Branch, 27 | Trigger = GitHubTrigger.POLL 28 | }), 29 | SynthAction = new SimpleSynthAction(new SimpleSynthActionProps() 30 | { 31 | Environment = new BuildEnvironment 32 | { 33 | // required for .NET 5 34 | // https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html 35 | BuildImage = LinuxBuildImage.STANDARD_5_0 36 | }, 37 | SourceArtifact = sourceArtifact, 38 | CloudAssemblyArtifact = cloudAssemblyArtifact, 39 | Subdirectory = "LambdaApiSolution", 40 | InstallCommands = new[] {"npm install -g aws-cdk"}, 41 | BuildCommands = new[] {"dotnet build src/LambdaApiSolution.sln"}, 42 | SynthCommand = "cdk synth" 43 | }) 44 | }); 45 | CdkStage developmentStage = pipeline.AddApplicationStage(new SolutionStage(this, "Development")); 46 | CdkStage testStage = pipeline.AddApplicationStage(new SolutionStage(this, "Test")); 47 | testStage.AddManualApprovalAction(new AddManualApprovalOptions() {ActionName = "PromoteToProduction"}); 48 | CdkStage productionStage = pipeline.AddApplicationStage(new SolutionStage(this, "Production")); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction/Readme.md: -------------------------------------------------------------------------------- 1 | # AWS Lambda Empty Docker Image Function Project 2 | 3 | This starter project consists of: 4 | * Function.cs - Class file containing a class with a single function handler method 5 | * Dockerfile - Used with the `docker build` command to build the docker image 6 | * aws-lambda-tools-defaults.json - default argument settings for use within Visual Studio and command line deployment tools for AWS 7 | 8 | You may also have a test project depending on the options selected. 9 | 10 | ## Packaging as a Docker image. 11 | 12 | This project is configured to package the Lambda function as a Docker image. The default configuration for the project and the Dockerfile is to build 13 | the .NET project on the host machine and then execute the `docker build` command which copies the .NET build artifacts from the host machine into 14 | the Docker image. 15 | 16 | The `--docker-host-build-output-dir` switch, which is set in the `aws-lambda-tools-defaults.json`, triggers the 17 | AWS .NET Lambda tooling to build the .NET project into the directory indicated by `--docker-host-build-output-dir`. The Dockerfile 18 | has a **COPY** command which copies the value from the directory pointed to by `--docker-host-build-output-dir` to the `/var/task` directory inside of the 19 | image. 20 | 21 | Alternatively the Docker file could be written to use [multi-stage](https://docs.docker.com/develop/develop-images/multistage-build/) builds and 22 | have the .NET project built inside the container. Below is an example of building .NET 5 project inside the image. 23 | 24 | ```dockerfile 25 | FROM ecr.aws/lambda/dotnet:5.0 AS base 26 | 27 | FROM mcr.microsoft.com/dotnet/sdk:5.0-buster-slim as build 28 | WORKDIR /src 29 | COPY ["BlueprintBaseName.csproj", "BlueprintBaseName/"] 30 | RUN dotnet restore "BlueprintBaseName/BlueprintBaseName.csproj" 31 | 32 | WORKDIR "/src/BlueprintBaseName" 33 | COPY . . 34 | RUN dotnet build "BlueprintBaseName.csproj" --configuration Release --output /app/build 35 | 36 | FROM build AS publish 37 | RUN dotnet publish "BlueprintBaseName.csproj" \ 38 | --configuration Release \ 39 | --runtime linux-x64 \ 40 | --self-contained false \ 41 | --output /app/publish \ 42 | -p:PublishReadyToRun=true 43 | 44 | FROM base AS final 45 | WORKDIR /var/task 46 | COPY --from=publish /app/publish . 47 | ``` 48 | 49 | When building the .NET project inside the image you must be sure to copy all of the class libraries the .NET Lambda project is depending on 50 | as well before the `dotnet build` step. The final published artifacts of the .NET project must be copied to the `/var/task` directory. 51 | The `--docker-host-build-output-dir` switch can also be removed from the `aws-lambda-tools-defaults.json` to avoid the 52 | .NET project from being built on the host machine before calling `docker build`. 53 | 54 | 55 | 56 | ## Here are some steps to follow from Visual Studio: 57 | 58 | To deploy your function to AWS Lambda, right click the project in Solution Explorer and select *Publish to AWS Lambda*. 59 | 60 | 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. 61 | 62 | To perform testing against your deployed function use the Test Invoke tab in the opened Function View window. 63 | 64 | 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. 65 | 66 | To update the runtime configuration of your deployed function use the Configuration tab in the opened Function View window. 67 | 68 | To view execution logs of invocations of your function use the Logs tab in the opened Function View window. 69 | 70 | ## Here are some steps to follow to get started from the command line: 71 | 72 | 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. Lambda function packaged as a Docker image require version 5.0.0 or later. 73 | 74 | Install Amazon.Lambda.Tools Global Tools if not already installed. 75 | ``` 76 | dotnet tool install -g Amazon.Lambda.Tools 77 | ``` 78 | 79 | If already installed check if new version is available. 80 | ``` 81 | dotnet tool update -g Amazon.Lambda.Tools 82 | ``` 83 | 84 | Execute unit tests 85 | ``` 86 | cd "BlueprintBaseName/test/BlueprintBaseName.Tests" 87 | dotnet test 88 | ``` 89 | 90 | Deploy function to AWS Lambda 91 | ``` 92 | cd "BlueprintBaseName/src/BlueprintBaseName" 93 | dotnet lambda deploy-function 94 | ``` 95 | -------------------------------------------------------------------------------- /LambdaApiSolution/src/LambdaApiSolution.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26124.0 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LambdaApiSolution", "LambdaApiSolution\LambdaApiSolution.csproj", "{7137D01D-9950-4D3E-8810-DA18A0B40501}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LambdaApiSolution.DockerFunction", "LambdaApiSolution.DockerFunction", "{78E7694F-C460-44A4-9676-AC310A00C92E}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{07EA4852-483D-4CFC-877C-BE044766EB79}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LambdaApiSolution.DockerFunction", "LambdaApiSolution.DockerFunction\src\LambdaApiSolution.DockerFunction\LambdaApiSolution.DockerFunction.csproj", "{597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B96957D2-DBAC-4F92-B7C9-5F403324B54B}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LambdaApiSolution.DockerFunction.Tests", "LambdaApiSolution.DockerFunction\test\LambdaApiSolution.DockerFunction.Tests\LambdaApiSolution.DockerFunction.Tests.csproj", "{CD8FCD6C-4A3C-41B0-A49B-589620E39454}" 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|Any CPU = Debug|Any CPU 21 | Debug|x64 = Debug|x64 22 | Debug|x86 = Debug|x86 23 | Release|Any CPU = Release|Any CPU 24 | Release|x64 = Release|x64 25 | Release|x86 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 31 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Debug|x64.ActiveCfg = Debug|Any CPU 34 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Debug|x64.Build.0 = Debug|Any CPU 35 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Debug|x86.ActiveCfg = Debug|Any CPU 36 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Debug|x86.Build.0 = Debug|Any CPU 37 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Release|Any CPU.ActiveCfg = Release|Any CPU 38 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Release|Any CPU.Build.0 = Release|Any CPU 39 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Release|x64.ActiveCfg = Release|Any CPU 40 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Release|x64.Build.0 = Release|Any CPU 41 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Release|x86.ActiveCfg = Release|Any CPU 42 | {7137D01D-9950-4D3E-8810-DA18A0B40501}.Release|x86.Build.0 = Release|Any CPU 43 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 44 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Debug|Any CPU.Build.0 = Debug|Any CPU 45 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Debug|x64.ActiveCfg = Debug|Any CPU 46 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Debug|x64.Build.0 = Debug|Any CPU 47 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Debug|x86.ActiveCfg = Debug|Any CPU 48 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Debug|x86.Build.0 = Debug|Any CPU 49 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Release|Any CPU.ActiveCfg = Release|Any CPU 50 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Release|Any CPU.Build.0 = Release|Any CPU 51 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Release|x64.ActiveCfg = Release|Any CPU 52 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Release|x64.Build.0 = Release|Any CPU 53 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Release|x86.ActiveCfg = Release|Any CPU 54 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5}.Release|x86.Build.0 = Release|Any CPU 55 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 56 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Debug|Any CPU.Build.0 = Debug|Any CPU 57 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Debug|x64.ActiveCfg = Debug|Any CPU 58 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Debug|x64.Build.0 = Debug|Any CPU 59 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Debug|x86.ActiveCfg = Debug|Any CPU 60 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Debug|x86.Build.0 = Debug|Any CPU 61 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Release|Any CPU.ActiveCfg = Release|Any CPU 62 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Release|Any CPU.Build.0 = Release|Any CPU 63 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Release|x64.ActiveCfg = Release|Any CPU 64 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Release|x64.Build.0 = Release|Any CPU 65 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Release|x86.ActiveCfg = Release|Any CPU 66 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454}.Release|x86.Build.0 = Release|Any CPU 67 | EndGlobalSection 68 | GlobalSection(NestedProjects) = preSolution 69 | {07EA4852-483D-4CFC-877C-BE044766EB79} = {78E7694F-C460-44A4-9676-AC310A00C92E} 70 | {597344E4-EAF7-4E2C-80B8-3FE6FD7F9FE5} = {07EA4852-483D-4CFC-877C-BE044766EB79} 71 | {B96957D2-DBAC-4F92-B7C9-5F403324B54B} = {78E7694F-C460-44A4-9676-AC310A00C92E} 72 | {CD8FCD6C-4A3C-41B0-A49B-589620E39454} = {B96957D2-DBAC-4F92-B7C9-5F403324B54B} 73 | EndGlobalSection 74 | EndGlobal 75 | -------------------------------------------------------------------------------- /LambdaApiSolution/.gitignore: -------------------------------------------------------------------------------- 1 | # CDK asset staging directory 2 | .cdk.staging 3 | cdk.out 4 | 5 | # Created by https://www.gitignore.io/api/csharp 6 | 7 | ### Csharp ### 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | ## 11 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 12 | 13 | # User-specific files 14 | *.suo 15 | *.user 16 | *.userosscache 17 | *.sln.docstates 18 | 19 | # User-specific files (MonoDevelop/Xamarin Studio) 20 | *.userprefs 21 | 22 | # Build results 23 | [Dd]ebug/ 24 | [Dd]ebugPublic/ 25 | [Rr]elease/ 26 | [Rr]eleases/ 27 | x64/ 28 | x86/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUNIT 47 | *.VisualState.xml 48 | TestResult.xml 49 | 50 | # Build Results of an ATL Project 51 | [Dd]ebugPS/ 52 | [Rr]eleasePS/ 53 | dlldata.c 54 | 55 | # Benchmark Results 56 | BenchmarkDotNet.Artifacts/ 57 | 58 | # .NET Core 59 | project.lock.json 60 | project.fragment.lock.json 61 | artifacts/ 62 | 63 | # StyleCop 64 | StyleCopReport.xml 65 | 66 | # Files built by Visual Studio 67 | *_i.c 68 | *_p.c 69 | *_i.h 70 | *.ilk 71 | *.meta 72 | *.obj 73 | *.iobj 74 | *.pch 75 | *.pdb 76 | *.ipdb 77 | *.pgc 78 | *.pgd 79 | *.rsp 80 | *.sbr 81 | *.tlb 82 | *.tli 83 | *.tlh 84 | *.tmp 85 | *.tmp_proj 86 | *.log 87 | *.vspscc 88 | *.vssscc 89 | .builds 90 | *.pidb 91 | *.svclog 92 | *.scc 93 | 94 | # Chutzpah Test files 95 | _Chutzpah* 96 | 97 | # Visual C++ cache files 98 | ipch/ 99 | *.aps 100 | *.ncb 101 | *.opendb 102 | *.opensdf 103 | *.sdf 104 | *.cachefile 105 | *.VC.db 106 | *.VC.VC.opendb 107 | 108 | # Visual Studio profiler 109 | *.psess 110 | *.vsp 111 | *.vspx 112 | *.sap 113 | 114 | # Visual Studio Trace Files 115 | *.e2e 116 | 117 | # TFS 2012 Local Workspace 118 | $tf/ 119 | 120 | # Guidance Automation Toolkit 121 | *.gpState 122 | 123 | # ReSharper is a .NET coding add-in 124 | _ReSharper*/ 125 | *.[Rr]e[Ss]harper 126 | *.DotSettings.user 127 | 128 | # JustCode is a .NET coding add-in 129 | .JustCode 130 | 131 | # TeamCity is a build add-in 132 | _TeamCity* 133 | 134 | # DotCover is a Code Coverage Tool 135 | *.dotCover 136 | 137 | # AxoCover is a Code Coverage Tool 138 | .axoCover/* 139 | !.axoCover/settings.json 140 | 141 | # Visual Studio code coverage results 142 | *.coverage 143 | *.coveragexml 144 | 145 | # NCrunch 146 | _NCrunch_* 147 | .*crunch*.local.xml 148 | nCrunchTemp_* 149 | 150 | # MightyMoose 151 | *.mm.* 152 | AutoTest.Net/ 153 | 154 | # Web workbench (sass) 155 | .sass-cache/ 156 | 157 | # Installshield output folder 158 | [Ee]xpress/ 159 | 160 | # DocProject is a documentation generator add-in 161 | DocProject/buildhelp/ 162 | DocProject/Help/*.HxT 163 | DocProject/Help/*.HxC 164 | DocProject/Help/*.hhc 165 | DocProject/Help/*.hhk 166 | DocProject/Help/*.hhp 167 | DocProject/Help/Html2 168 | DocProject/Help/html 169 | 170 | # Click-Once directory 171 | publish/ 172 | 173 | # Publish Web Output 174 | *.[Pp]ublish.xml 175 | *.azurePubxml 176 | # Note: Comment the next line if you want to checkin your web deploy settings, 177 | # but database connection strings (with potential passwords) will be unencrypted 178 | *.pubxml 179 | *.publishproj 180 | 181 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 182 | # checkin your Azure Web App publish settings, but sensitive information contained 183 | # in these scripts will be unencrypted 184 | PublishScripts/ 185 | 186 | # NuGet Packages 187 | *.nupkg 188 | # The packages folder can be ignored because of Package Restore 189 | **/[Pp]ackages/* 190 | # except build/, which is used as an MSBuild target. 191 | !**/[Pp]ackages/build/ 192 | # Uncomment if necessary however generally it will be regenerated when needed 193 | #!**/[Pp]ackages/repositories.config 194 | # NuGet v3's project.json files produces more ignorable files 195 | *.nuget.props 196 | *.nuget.targets 197 | 198 | # Microsoft Azure Build Output 199 | csx/ 200 | *.build.csdef 201 | 202 | # Microsoft Azure Emulator 203 | ecf/ 204 | rcf/ 205 | 206 | # Windows Store app package directories and files 207 | AppPackages/ 208 | BundleArtifacts/ 209 | Package.StoreAssociation.xml 210 | _pkginfo.txt 211 | *.appx 212 | 213 | # Visual Studio cache files 214 | # files ending in .cache can be ignored 215 | *.[Cc]ache 216 | # but keep track of directories ending in .cache 217 | !*.[Cc]ache/ 218 | 219 | # Others 220 | ClientBin/ 221 | ~$* 222 | *~ 223 | *.dbmdl 224 | *.dbproj.schemaview 225 | *.jfm 226 | *.pfx 227 | *.publishsettings 228 | orleans.codegen.cs 229 | 230 | # Including strong name files can present a security risk 231 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 232 | #*.snk 233 | 234 | # Since there are multiple workflows, uncomment next line to ignore bower_components 235 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 236 | #bower_components/ 237 | 238 | # RIA/Silverlight projects 239 | Generated_Code/ 240 | 241 | # Backup & report files from converting an old project file 242 | # to a newer Visual Studio version. Backup files are not needed, 243 | # because we have git ;-) 244 | _UpgradeReport_Files/ 245 | Backup*/ 246 | UpgradeLog*.XML 247 | UpgradeLog*.htm 248 | ServiceFabricBackup/ 249 | *.rptproj.bak 250 | 251 | # SQL Server files 252 | *.mdf 253 | *.ldf 254 | *.ndf 255 | 256 | # Business Intelligence projects 257 | *.rdl.data 258 | *.bim.layout 259 | *.bim_*.settings 260 | *.rptproj.rsuser 261 | 262 | # Microsoft Fakes 263 | FakesAssemblies/ 264 | 265 | # GhostDoc plugin setting file 266 | *.GhostDoc.xml 267 | 268 | # Node.js Tools for Visual Studio 269 | .ntvs_analysis.dat 270 | node_modules/ 271 | 272 | # Visual Studio 6 build log 273 | *.plg 274 | 275 | # Visual Studio 6 workspace options file 276 | *.opt 277 | 278 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 279 | *.vbw 280 | 281 | # Visual Studio LightSwitch build output 282 | **/*.HTMLClient/GeneratedArtifacts 283 | **/*.DesktopClient/GeneratedArtifacts 284 | **/*.DesktopClient/ModelManifest.xml 285 | **/*.Server/GeneratedArtifacts 286 | **/*.Server/ModelManifest.xml 287 | _Pvt_Extensions 288 | 289 | # Paket dependency manager 290 | .paket/paket.exe 291 | paket-files/ 292 | 293 | # FAKE - F# Make 294 | .fake/ 295 | 296 | # JetBrains Rider 297 | .idea/ 298 | *.sln.iml 299 | 300 | # CodeRush 301 | .cr/ 302 | 303 | # Python Tools for Visual Studio (PTVS) 304 | __pycache__/ 305 | *.pyc 306 | 307 | # Cake - Uncomment if you are using it 308 | # tools/** 309 | # !tools/packages.config 310 | 311 | # Tabs Studio 312 | *.tss 313 | 314 | # Telerik's JustMock configuration file 315 | *.jmconfig 316 | 317 | # BizTalk build output 318 | *.btp.cs 319 | *.btm.cs 320 | *.odx.cs 321 | *.xsd.cs 322 | 323 | # OpenCover UI analysis results 324 | OpenCover/ 325 | 326 | # Azure Stream Analytics local run output 327 | ASALocalRun/ 328 | 329 | # MSBuild Binary and Structured Log 330 | *.binlog 331 | 332 | # NVidia Nsight GPU debugger configuration file 333 | *.nvuser 334 | 335 | # MFractors (Xamarin productivity tool) working folder 336 | .mfractor/ 337 | 338 | # Local History for Visual Studio 339 | .localhistory/ 340 | 341 | 342 | # End of https://www.gitignore.io/api/csharp -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | 352 | # IDEs 353 | .idea/ 354 | .vscode/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Deciding on Which Technology to Use 2 | While infrastructure as code (IaC) has existed within the AWS ecosystem since 2011, adoption has exploded recently due to the ability to manage large amounts of infrastructure at scale and standardize design across an organization. There are almost too many options between CloudFormation (CFN), CDK, and Terraform for IaC and Serverless Application Model (SAM) and Serverless Framework for development. [This article](https://acloudguru.com/blog/engineering/cloudformation-terraform-or-cdk-guide-to-iac-on-aws) from A Cloud Guru quickly sums up the pros and cons of each option. I choose this particular stack for some key reasons: 3 | - CDK allows the infrastructure and the CI/CD pipeline to be described as C# instead of YAML, JSON, or [HCL](https://www.terraform.io/docs/language/syntax/configuration.html) 4 | - CDK provides the ability to inject more robust logic than intrinsic functions in CloudFormation and more modularity as well while still being a native AWS offering 5 | - Docker ensures that the Lambda functions run consistently across local development, builds, and production environments and simplifies dependency management 6 | - [CDK Pipelines](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_pipelines.CdkPipeline.html) offer a higher level construct with much less configuration than CodePipeline and streamline management of multiple environments 7 | 8 | ## GitHub Repository 9 | You can find a complete working example [here](https://github.com/scottenriquez/dotnet-5-lambda-api-cdk). 10 | 11 | ## Initializing the Project 12 | Ensure that .NET 5 and the latest version of CDK are installed. To create a solution skeleton, run these commands in the root directory: 13 | 14 | ```shell 15 | # note that CDK uses this directory name as the solution name 16 | mkdir LambdaApiSolution 17 | cd LambdaApiSolution 18 | cdk init app --language=csharp 19 | # creates a CFN stack called CDKToolkit with an S3 bucket for staging purposes and configures IAM permissions for CI/CD 20 | cdk bootstrap --cloudformation-execution-policies arn:aws:iam::aws:policy/AdministratorAccess 21 | cdk deploy 22 | ``` 23 | 24 | In order to use CDK Pipelines later on, a specific flag needs to be added to `cdk.json`: 25 | ```json 26 | { 27 | "app": "dotnet run -p src/LambdaApiSolution/LambdaApiSolution.csproj", 28 | "context": { 29 | .. 30 | "@aws-cdk/core:newStyleStackSynthesis": "true", 31 | .. 32 | } 33 | } 34 | ``` 35 | 36 | At the time of writing, the generated CDK template uses .NET Core 3.1. Inside of the `.csproj` file, change the `TargetFramework` tag to `net5.0`. 37 | 38 | ```xml 39 | 40 | 41 | Exe 42 | net5.0 43 | 44 | 45 | ``` 46 | 47 | From the `/LambdaApiSolution` directory, run these commands to create the serverless skeleton: 48 | 49 | ```shell 50 | # install the latest version of the .NET Lambda templates 51 | dotnet new -i Amazon.Lambda.Templates 52 | cd src/ 53 | # create the function 54 | dotnet new lambda.image.EmptyFunction --name LambdaApiSolution.DockerFunction 55 | # add the projects to the solution file 56 | dotnet sln add LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction/LambdaApiSolution.DockerFunction.csproj 57 | dotnet sln add LambdaApiSolution.DockerFunction/test/LambdaApiSolution.DockerFunction.Tests/LambdaApiSolution.DockerFunction.Tests.csproj 58 | # build the solution and run the sample unit test to verify that everything is wired up correctly 59 | dotnet test LambdaApiSolution.sln 60 | ``` 61 | 62 | ## Creating the Lambda Infrastructure and Build 63 | First, add the Lambda CDK NuGet package to the CDK project. 64 | 65 | ```xml 66 | 67 | ``` 68 | 69 | Then, create the Docker image and Lambda function using CDK constructs in `LambdaApiSolutionStack.cs`: 70 | 71 | ```csharp 72 | public class LambdaApiSolutionStack : Stack 73 | { 74 | internal LambdaApiSolutionStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) 75 | { 76 | // this path is relative to the directory where CDK commands are run 77 | // the directory must contain a Dockerfile 78 | DockerImageCode dockerImageCode = DockerImageCode.FromImageAsset("src/LambdaApiSolution.DockerFunction/src/LambdaApiSolution.DockerFunction"); 79 | DockerImageFunction dockerImageFunction = new DockerImageFunction(this, "LambdaFunction", new DockerImageFunctionProps() 80 | { 81 | Code = dockerImageCode, 82 | Description = ".NET 5 Docker Lambda function" 83 | }); 84 | } 85 | } 86 | ``` 87 | 88 | Lastly, update the `Dockerfile` in the Lambda function project like so to build the C# code: 89 | 90 | ```dockerfile 91 | FROM public.ecr.aws/lambda/dotnet:5.0 92 | FROM mcr.microsoft.com/dotnet/sdk:5.0 as build-image 93 | 94 | ARG FUNCTION_DIR="/build" 95 | ARG CONFIGURATION="release" 96 | ENV PATH="/root/.dotnet/tools:${PATH}" 97 | 98 | RUN apt-get update && apt-get -y install zip 99 | 100 | RUN mkdir $FUNCTION_DIR 101 | WORKDIR $FUNCTION_DIR 102 | COPY Function.cs LambdaApiSolution.DockerFunction.csproj aws-lambda-tools-defaults.json $FUNCTION_DIR/ 103 | RUN dotnet tool install -g Amazon.Lambda.Tools 104 | 105 | RUN mkdir -p build_artifacts 106 | RUN if [ "$CONFIGURATION" = "debug" ]; then dotnet lambda package --configuration Debug --package-type zip; else dotnet lambda package --configuration Release --package-type zip; fi 107 | RUN if [ "$CONFIGURATION" = "debug" ]; then cp -r /build/bin/Debug/net5.0/publish/* /build/build_artifacts; else cp -r /build/bin/Release/net5.0/publish/* /build/build_artifacts; fi 108 | 109 | FROM public.ecr.aws/lambda/dotnet:5.0 110 | 111 | COPY --from=build-image /build/build_artifacts/ /var/task/ 112 | CMD ["LambdaApiSolution.DockerFunction::LambdaApiSolution.DockerFunction.Function::FunctionHandler"] 113 | ``` 114 | 115 | At this point, you can now deploy the changes with the `cdk deploy` command. The Lambda function can be tested via the AWS Console. The easiest way to do so is to navigate to the CloudFormation stack, click on the function resource, and then create a test event with the string `"hello"` as the input. Note that this should not be a JSON object because the event handler's parameter currently accepts a single string. 116 | 117 | ## Integrating API Gateway 118 | Add the following packages to the CDK project: 119 | 120 | ```xml 121 | 122 | 123 | ``` 124 | 125 | Next, you can add the API Gateway resources to the stack immediately after the `DockerImageFunction` in `LambdaApiSolutionStack.cs`: 126 | 127 | ```csharp 128 | HttpApi httpApi = new HttpApi(this, "APIGatewayForLambda", new HttpApiProps() 129 | { 130 | ApiName = "APIGatewayForLambda", 131 | CreateDefaultStage = true, 132 | CorsPreflight = new CorsPreflightOptions() 133 | { 134 | AllowMethods = new [] { HttpMethod.GET }, 135 | AllowOrigins = new [] { "*" }, 136 | MaxAge = Duration.Days(10) 137 | } 138 | }); 139 | ``` 140 | Then, create a Lambda proxy integration and a route for the function: 141 | 142 | ```csharp 143 | LambdaProxyIntegration lambdaProxyIntegration = new LambdaProxyIntegration(new LambdaProxyIntegrationProps() 144 | { 145 | Handler = dockerImageFunction, 146 | PayloadFormatVersion = PayloadFormatVersion.VERSION_2_0 147 | }); 148 | httpApi.AddRoutes(new AddRoutesOptions() 149 | { 150 | Path = "/casing", 151 | Integration = lambdaProxyIntegration, 152 | Methods = new [] { HttpMethod.POST } 153 | }); 154 | ``` 155 | 156 | I used `/casing` for the path since the sample Lambda function returns an upper and lower case version of the input string. Finally, it's helpful to display the endpoint URL using a CFN output for testing. 157 | 158 | ```csharp 159 | // adding entropy to prevent a name collision 160 | string guid = Guid.NewGuid().ToString(); 161 | CfnOutput apiUrl = new CfnOutput(this, "APIGatewayURLOutput", new CfnOutputProps() 162 | { 163 | ExportName = $"APIGatewayEndpointURL-{guid}", 164 | Value = httpApi.ApiEndpoint 165 | }); 166 | ``` 167 | 168 | With these changes to the resources, the Lambda function can be invoked by a `POST` request. The handler method parameters in `Function.cs` need to be updated for the request body to be passed in. 169 | 170 | ```csharp 171 | // replace the string parameter with a proxy request parameter 172 | public Casing FunctionHandler(APIGatewayProxyRequest apiGatewayProxyRequest, ILambdaContext context) 173 | { 174 | // update the input to use the proxy 175 | string input = apiGatewayProxyRequest.Body; 176 | return new Casing(input.ToLower(), input.ToUpper()); 177 | } 178 | ``` 179 | 180 | After successfully deploying the changes, the function can be tested in two ways. The first way is through an HTTP client like Postman. Add a string to the body parameter of the `POST` request. This action tests the full integration with API Gateway as well as the Lambda function. To test via the Lambda Console, update the test event from before to match the `APIGatewayProxyRequest` parameter: 181 | 182 | ```json 183 | { 184 | "body": "hello" 185 | } 186 | ``` 187 | 188 | ## Adding CI/CD Using CDK Pipelines 189 | For this example, the source code resides in GitHub as opposed to CodeCommit. To grant the CI/CD pipeline access to the repository, a personal access token with `repo` permissions must be created via GitHub and stored in Secrets Manager as a plaintext format object. Note that for this codebase, I've named my secret `GitHub-Token`. 190 | 191 | Next, add the following packages to the CDK project: 192 | ```xml 193 | 194 | 195 | 196 | 197 | 198 | ``` 199 | 200 | With these dependencies loaded, create a class called `PipelineStack.cs`. The following code creates a self-mutating CDK Pipeline, adds a GitHub source action to fetch the code using the token from Secrets Manager, and synthesizes the solution's CDK: 201 | 202 | ```csharp 203 | using Amazon.CDK; 204 | using Amazon.CDK.AWS.CodeBuild; 205 | using Amazon.CDK.AWS.CodePipeline; 206 | using Amazon.CDK.AWS.CodePipeline.Actions; 207 | using Amazon.CDK.Pipelines; 208 | 209 | namespace LambdaApiSolution 210 | { 211 | public class PipelineStack : Stack 212 | { 213 | internal PipelineStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) 214 | { 215 | Artifact_ sourceArtifact = new Artifact_(); 216 | Artifact_ cloudAssemblyArtifact = new Artifact_(); 217 | CdkPipeline pipeline = new CdkPipeline(this, "LambdaApiSolutionPipeline", new CdkPipelineProps() 218 | { 219 | CloudAssemblyArtifact = cloudAssemblyArtifact, 220 | PipelineName = "LambdaApiSolutionPipeline", 221 | SourceAction = new GitHubSourceAction(new GitHubSourceActionProps() 222 | { 223 | ActionName = "GitHubSource", 224 | Output = sourceArtifact, 225 | OauthToken = SecretValue.SecretsManager(Constants.GitHubTokenSecretsManagerId), 226 | Owner = Constants.Owner, 227 | Repo = Constants.RepositoryName, 228 | Branch = Constants.Branch, 229 | Trigger = GitHubTrigger.POLL 230 | }), 231 | SynthAction = new SimpleSynthAction(new SimpleSynthActionProps() 232 | { 233 | Environment = new BuildEnvironment 234 | { 235 | // required for .NET 5 236 | // https://docs.aws.amazon.com/codebuild/latest/userguide/build-env-ref-available.html 237 | BuildImage = LinuxBuildImage.STANDARD_5_0 238 | }, 239 | SourceArtifact = sourceArtifact, 240 | CloudAssemblyArtifact = cloudAssemblyArtifact, 241 | Subdirectory = "LambdaApiSolution", 242 | InstallCommands = new[] {"npm install -g aws-cdk"}, 243 | BuildCommands = new[] {"dotnet build src/LambdaApiSolution.sln"}, 244 | SynthCommand = "cdk synth" 245 | }) 246 | }); 247 | } 248 | } 249 | } 250 | 251 | ``` 252 | 253 | Remove the following line from `Program.cs` since the pipeline will deploy the API from now on: 254 | ```csharp 255 | new LambdaApiSolutionStack(app, "LambdaApiSolutionStack"); 256 | ``` 257 | 258 | Delete the previous stack, commit the latest changes to the source code so that they'll be available when the pipeline fetches the repo, and finally deploy the pipeline: 259 | 260 | ```shell 261 | cdk destroy 262 | git add . 263 | git commit -m "Adding source code to GitHub repository" 264 | git push origin main 265 | cdk deploy LambdaApiSolutionPipelineStack 266 | ``` 267 | 268 | ## Creating Multiple Environments 269 | From now on, the pipeline will manage changes instead of manual `cdk deploy` commands. By merely pushing changes to the `main` branch, the pipeline will update itself and the other resources. The last feature in this example is adding development, test, and production environments. Rather than creating more stacks, we can leverage stages instead. Each environment will have a stage that makes a separate stack plus actions like approvals or integration testing. First, a stage must be defined in code. For this example, a stage will only contain an API stack. 270 | 271 | ```csharp 272 | using Amazon.CDK; 273 | using Construct = Constructs.Construct; 274 | 275 | namespace LambdaApiSolution 276 | { 277 | public class SolutionStage : Stage 278 | { 279 | public SolutionStage(Construct scope, string id, IStageProps props = null) : base(scope, id, props) 280 | { 281 | LambdaApiSolutionStack lambdaApiSolutionStack = new LambdaApiSolutionStack(this, "Solution"); 282 | } 283 | } 284 | } 285 | ``` 286 | 287 | To implement the stages, navigate back to `PipelineStack.cs` and append the following code after the pipeline declaration: 288 | 289 | ```csharp 290 | CdkStage developmentStage = pipeline.AddApplicationStage(new SolutionStage(this, "Development")); 291 | CdkStage testStage = pipeline.AddApplicationStage(new SolutionStage(this, "Test")); 292 | testStage.AddManualApprovalAction(new AddManualApprovalOptions() 293 | { 294 | ActionName = "PromoteToProduction" 295 | }); 296 | CdkStage productionStage = pipeline.AddApplicationStage(new SolutionStage(this, "Production")); 297 | ``` 298 | 299 | ## Next Steps 300 | The Lambda function, API Gateway, and multi-environment CI/CD pipeline are now in place. More Lambda functions can be added as separate C# projects. More stacks can be created and added to `SolutionStage.cs`. -------------------------------------------------------------------------------- /LambdaApiSolution/src/.editorconfig: -------------------------------------------------------------------------------- 1 | ########################################## 2 | # Common Settings 3 | ########################################## 4 | 5 | # This file is the top-most EditorConfig file 6 | root = true 7 | 8 | # All Files 9 | [*] 10 | charset = utf-8 11 | indent_style = tab 12 | indent_size = 3 13 | insert_final_newline = true 14 | trim_trailing_whitespace = true 15 | 16 | ########################################## 17 | # File Extension Settings 18 | ########################################## 19 | 20 | # Visual Studio Solution Files 21 | [*.sln] 22 | indent_style = tab 23 | 24 | # Visual Studio XML Project Files 25 | [*.{csproj,vbproj,vcxproj.filters,proj,projitems,shproj}] 26 | indent_size = 2 27 | 28 | # XML Configuration Files 29 | [*.{xml,config,props,targets,nuspec,resx,ruleset,vsixmanifest,vsct}] 30 | indent_size = 2 31 | 32 | # JSON Files 33 | [*.{json,json5,webmanifest}] 34 | indent_size = 2 35 | 36 | # YAML Files 37 | [*.{yml,yaml}] 38 | indent_size = 2 39 | 40 | # Markdown Files 41 | [*.md] 42 | trim_trailing_whitespace = false 43 | 44 | # Web Files 45 | [*.{htm,html,js,jsm,ts,tsx,css,sass,scss,less,svg,vue}] 46 | indent_size = 2 47 | 48 | # Batch Files 49 | [*.{cmd,bat}] 50 | end_of_line = crlf 51 | 52 | # Bash Files 53 | [*.sh] 54 | end_of_line = lf 55 | 56 | # Makefiles 57 | [Makefile] 58 | indent_style = tab 59 | 60 | ########################################## 61 | # Default .NET Code Style Severities 62 | # https://docs.microsoft.com/dotnet/fundamentals/code-analysis/configuration-options#scope 63 | ########################################## 64 | 65 | [*.{cs,csx,cake,vb,vbx}] 66 | # Default Severity for all .NET Code Style rules below 67 | dotnet_analyzer_diagnostic.severity = warning 68 | 69 | ########################################## 70 | # File Header (Uncomment to support file headers) 71 | # https://docs.microsoft.com/visualstudio/ide/reference/add-file-header 72 | ########################################## 73 | 74 | # [*.{cs,csx,cake,vb,vbx}] 75 | # file_header_template = \n© PROJECT-AUTHOR\n 76 | 77 | # SA1636: File header copyright text should match 78 | # Justification: .editorconfig supports file headers. If this is changed to a value other than "none", a stylecop.json file will need to added to the project. 79 | # dotnet_diagnostic.SA1636.severity = none 80 | 81 | ########################################## 82 | # .NET Language Conventions 83 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions 84 | ########################################## 85 | 86 | # .NET Code Style Settings 87 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#net-code-style-settings 88 | [*.{cs,csx,cake,vb,vbx}] 89 | # "this." and "Me." qualifiers 90 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#this-and-me 91 | dotnet_style_qualification_for_field = true:warning 92 | dotnet_style_qualification_for_property = true:warning 93 | dotnet_style_qualification_for_method = true:warning 94 | dotnet_style_qualification_for_event = true:warning 95 | # Language keywords instead of framework type names for type references 96 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#language-keywords 97 | dotnet_style_predefined_type_for_locals_parameters_members = true:warning 98 | dotnet_style_predefined_type_for_member_access = true:warning 99 | # Modifier preferences 100 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#normalize-modifiers 101 | dotnet_style_require_accessibility_modifiers = always:warning 102 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning 103 | visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:warning 104 | dotnet_style_readonly_field = true:warning 105 | # Parentheses preferences 106 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parentheses-preferences 107 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning 108 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning 109 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning 110 | dotnet_style_parentheses_in_other_operators = always_for_clarity:suggestion 111 | # Expression-level preferences 112 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences 113 | dotnet_style_object_initializer = true:warning 114 | dotnet_style_collection_initializer = true:warning 115 | dotnet_style_explicit_tuple_names = true:warning 116 | dotnet_style_prefer_inferred_tuple_names = true:warning 117 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:warning 118 | dotnet_style_prefer_auto_properties = true:warning 119 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning 120 | dotnet_style_prefer_conditional_expression_over_assignment = false:suggestion 121 | dotnet_diagnostic.IDE0045.severity = suggestion 122 | dotnet_style_prefer_conditional_expression_over_return = false:suggestion 123 | dotnet_diagnostic.IDE0046.severity = suggestion 124 | dotnet_style_prefer_compound_assignment = true:warning 125 | # Null-checking preferences 126 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#null-checking-preferences 127 | dotnet_style_coalesce_expression = true:warning 128 | dotnet_style_null_propagation = true:warning 129 | # Parameter preferences 130 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#parameter-preferences 131 | dotnet_code_quality_unused_parameters = all:warning 132 | # More style options (Undocumented) 133 | # https://github.com/MicrosoftDocs/visualstudio-docs/issues/3641 134 | dotnet_style_operator_placement_when_wrapping = end_of_line 135 | # https://github.com/dotnet/roslyn/pull/40070 136 | dotnet_style_prefer_simplified_interpolation = true:warning 137 | 138 | # C# Code Style Settings 139 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-code-style-settings 140 | [*.{cs,csx,cake}] 141 | # Expression-bodied members 142 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-bodied-members 143 | csharp_style_expression_bodied_methods = true:warning 144 | csharp_style_expression_bodied_constructors = true:warning 145 | csharp_style_expression_bodied_operators = true:warning 146 | csharp_style_expression_bodied_properties = true:warning 147 | csharp_style_expression_bodied_indexers = true:warning 148 | csharp_style_expression_bodied_accessors = true:warning 149 | csharp_style_expression_bodied_lambdas = true:warning 150 | csharp_style_expression_bodied_local_functions = true:warning 151 | # Pattern matching 152 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#pattern-matching 153 | csharp_style_pattern_matching_over_is_with_cast_check = true:warning 154 | csharp_style_pattern_matching_over_as_with_null_check = true:warning 155 | # Inlined variable declarations 156 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#inlined-variable-declarations 157 | csharp_style_inlined_variable_declaration = true:warning 158 | # Expression-level preferences 159 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#expression-level-preferences 160 | csharp_prefer_simple_default_expression = true:warning 161 | # "Null" checking preferences 162 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#c-null-checking-preferences 163 | csharp_style_throw_expression = true:warning 164 | csharp_style_conditional_delegate_call = true:warning 165 | # Code block preferences 166 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#code-block-preferences 167 | csharp_prefer_braces = true:warning 168 | # Unused value preferences 169 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#unused-value-preferences 170 | csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion 171 | dotnet_diagnostic.IDE0058.severity = suggestion 172 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 173 | dotnet_diagnostic.IDE0059.severity = suggestion 174 | # Index and range preferences 175 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#index-and-range-preferences 176 | csharp_style_prefer_index_operator = true:warning 177 | csharp_style_prefer_range_operator = true:warning 178 | # Miscellaneous preferences 179 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-language-conventions#miscellaneous-preferences 180 | csharp_style_deconstructed_variable_declaration = true:warning 181 | csharp_style_pattern_local_over_anonymous_function = true:warning 182 | csharp_using_directive_placement = inside_namespace:warning 183 | csharp_prefer_static_local_function = true:warning 184 | csharp_prefer_simple_using_statement = true:suggestion 185 | dotnet_diagnostic.IDE0063.severity = suggestion 186 | 187 | ########################################## 188 | # .NET Formatting Conventions 189 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-code-style-settings-reference#formatting-conventions 190 | ########################################## 191 | 192 | # Organize usings 193 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#organize-using-directives 194 | dotnet_sort_system_directives_first = true 195 | # Newline options 196 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#new-line-options 197 | csharp_new_line_before_open_brace = all 198 | csharp_new_line_before_else = true 199 | csharp_new_line_before_catch = true 200 | csharp_new_line_before_finally = true 201 | csharp_new_line_before_members_in_object_initializers = true 202 | csharp_new_line_before_members_in_anonymous_types = true 203 | csharp_new_line_between_query_expression_clauses = true 204 | # Indentation options 205 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#indentation-options 206 | csharp_indent_case_contents = true 207 | csharp_indent_switch_labels = true 208 | csharp_indent_labels = no_change 209 | csharp_indent_block_contents = true 210 | csharp_indent_braces = false 211 | csharp_indent_case_contents_when_block = false 212 | # Spacing options 213 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#spacing-options 214 | csharp_space_after_cast = false 215 | csharp_space_after_keywords_in_control_flow_statements = true 216 | csharp_space_between_parentheses = false 217 | csharp_space_before_colon_in_inheritance_clause = true 218 | csharp_space_after_colon_in_inheritance_clause = true 219 | csharp_space_around_binary_operators = before_and_after 220 | csharp_space_between_method_declaration_parameter_list_parentheses = false 221 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 222 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 223 | csharp_space_between_method_call_parameter_list_parentheses = false 224 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 225 | csharp_space_between_method_call_name_and_opening_parenthesis = false 226 | csharp_space_after_comma = true 227 | csharp_space_before_comma = false 228 | csharp_space_after_dot = false 229 | csharp_space_before_dot = false 230 | csharp_space_after_semicolon_in_for_statement = true 231 | csharp_space_before_semicolon_in_for_statement = false 232 | csharp_space_around_declaration_statements = false 233 | csharp_space_before_open_square_brackets = false 234 | csharp_space_between_empty_square_brackets = false 235 | csharp_space_between_square_brackets = false 236 | # Wrapping options 237 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-formatting-conventions#wrap-options 238 | csharp_preserve_single_line_statements = false 239 | csharp_preserve_single_line_blocks = true 240 | 241 | ########################################## 242 | # .NET Naming Conventions 243 | # https://docs.microsoft.com/visualstudio/ide/editorconfig-naming-conventions 244 | ########################################## 245 | 246 | [*.{cs,csx,cake,vb,vbx}] 247 | 248 | ########################################## 249 | # Styles 250 | ########################################## 251 | 252 | # camel_case_style - Define the camelCase style 253 | dotnet_naming_style.camel_case_style.capitalization = camel_case 254 | # pascal_case_style - Define the PascalCase style 255 | dotnet_naming_style.pascal_case_style.capitalization = pascal_case 256 | # first_upper_style - The first character must start with an upper-case character 257 | dotnet_naming_style.first_upper_style.capitalization = first_word_upper 258 | # prefix_interface_with_i_style - Interfaces must be PascalCase and the first character of an interface must be an 'I' 259 | dotnet_naming_style.prefix_interface_with_i_style.capitalization = pascal_case 260 | dotnet_naming_style.prefix_interface_with_i_style.required_prefix = I 261 | # prefix_type_parameters_with_t_style - Generic Type Parameters must be PascalCase and the first character must be a 'T' 262 | dotnet_naming_style.prefix_type_parameters_with_t_style.capitalization = pascal_case 263 | dotnet_naming_style.prefix_type_parameters_with_t_style.required_prefix = T 264 | # disallowed_style - Anything that has this style applied is marked as disallowed 265 | dotnet_naming_style.disallowed_style.capitalization = pascal_case 266 | dotnet_naming_style.disallowed_style.required_prefix = ____RULE_VIOLATION____ 267 | dotnet_naming_style.disallowed_style.required_suffix = ____RULE_VIOLATION____ 268 | # internal_error_style - This style should never occur... if it does, it indicates a bug in file or in the parser using the file 269 | dotnet_naming_style.internal_error_style.capitalization = pascal_case 270 | dotnet_naming_style.internal_error_style.required_prefix = ____INTERNAL_ERROR____ 271 | dotnet_naming_style.internal_error_style.required_suffix = ____INTERNAL_ERROR____ 272 | 273 | ########################################## 274 | # .NET Design Guideline Field Naming Rules 275 | # Naming rules for fields follow the .NET Framework design guidelines 276 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/index 277 | ########################################## 278 | 279 | # All public/protected/protected_internal constant fields must be PascalCase 280 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field 281 | dotnet_naming_symbols.public_protected_constant_fields_group.applicable_accessibilities = public, protected, protected_internal 282 | dotnet_naming_symbols.public_protected_constant_fields_group.required_modifiers = const 283 | dotnet_naming_symbols.public_protected_constant_fields_group.applicable_kinds = field 284 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.symbols = public_protected_constant_fields_group 285 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.style = pascal_case_style 286 | dotnet_naming_rule.public_protected_constant_fields_must_be_pascal_case_rule.severity = warning 287 | 288 | # All public/protected/protected_internal static readonly fields must be PascalCase 289 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field 290 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_accessibilities = public, protected, protected_internal 291 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.required_modifiers = static, readonly 292 | dotnet_naming_symbols.public_protected_static_readonly_fields_group.applicable_kinds = field 293 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.symbols = public_protected_static_readonly_fields_group 294 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style 295 | dotnet_naming_rule.public_protected_static_readonly_fields_must_be_pascal_case_rule.severity = warning 296 | 297 | # No other public/protected/protected_internal fields are allowed 298 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/field 299 | dotnet_naming_symbols.other_public_protected_fields_group.applicable_accessibilities = public, protected, protected_internal 300 | dotnet_naming_symbols.other_public_protected_fields_group.applicable_kinds = field 301 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.symbols = other_public_protected_fields_group 302 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.style = disallowed_style 303 | dotnet_naming_rule.other_public_protected_fields_disallowed_rule.severity = error 304 | 305 | ########################################## 306 | # StyleCop Field Naming Rules 307 | # Naming rules for fields follow the StyleCop analyzers 308 | # This does not override any rules using disallowed_style above 309 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers 310 | ########################################## 311 | 312 | # All constant fields must be PascalCase 313 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1303.md 314 | dotnet_naming_symbols.stylecop_constant_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private 315 | dotnet_naming_symbols.stylecop_constant_fields_group.required_modifiers = const 316 | dotnet_naming_symbols.stylecop_constant_fields_group.applicable_kinds = field 317 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.symbols = stylecop_constant_fields_group 318 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.style = pascal_case_style 319 | dotnet_naming_rule.stylecop_constant_fields_must_be_pascal_case_rule.severity = warning 320 | 321 | # All static readonly fields must be PascalCase 322 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1311.md 323 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected, private 324 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.required_modifiers = static, readonly 325 | dotnet_naming_symbols.stylecop_static_readonly_fields_group.applicable_kinds = field 326 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.symbols = stylecop_static_readonly_fields_group 327 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.style = pascal_case_style 328 | dotnet_naming_rule.stylecop_static_readonly_fields_must_be_pascal_case_rule.severity = warning 329 | 330 | # No non-private instance fields are allowed 331 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md 332 | dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_accessibilities = public, internal, protected_internal, protected, private_protected 333 | dotnet_naming_symbols.stylecop_fields_must_be_private_group.applicable_kinds = field 334 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.symbols = stylecop_fields_must_be_private_group 335 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.style = disallowed_style 336 | dotnet_naming_rule.stylecop_instance_fields_must_be_private_rule.severity = error 337 | 338 | # Private fields must be camelCase 339 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md 340 | dotnet_naming_symbols.stylecop_private_fields_group.applicable_accessibilities = private 341 | dotnet_naming_symbols.stylecop_private_fields_group.applicable_kinds = field 342 | dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.symbols = stylecop_private_fields_group 343 | dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.style = camel_case_style 344 | dotnet_naming_rule.stylecop_private_fields_must_be_camel_case_rule.severity = warning 345 | 346 | # Local variables must be camelCase 347 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md 348 | dotnet_naming_symbols.stylecop_local_fields_group.applicable_accessibilities = local 349 | dotnet_naming_symbols.stylecop_local_fields_group.applicable_kinds = local 350 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.symbols = stylecop_local_fields_group 351 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.style = camel_case_style 352 | dotnet_naming_rule.stylecop_local_fields_must_be_camel_case_rule.severity = silent 353 | 354 | # This rule should never fire. However, it's included for at least two purposes: 355 | # First, it helps to understand, reason about, and root-case certain types of issues, such as bugs in .editorconfig parsers. 356 | # Second, it helps to raise immediate awareness if a new field type is added (as occurred recently in C#). 357 | dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_accessibilities = * 358 | dotnet_naming_symbols.sanity_check_uncovered_field_case_group.applicable_kinds = field 359 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.symbols = sanity_check_uncovered_field_case_group 360 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.style = internal_error_style 361 | dotnet_naming_rule.sanity_check_uncovered_field_case_rule.severity = error 362 | 363 | 364 | ########################################## 365 | # Other Naming Rules 366 | ########################################## 367 | 368 | # All of the following must be PascalCase: 369 | # - Namespaces 370 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-namespaces 371 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md 372 | # - Classes and Enumerations 373 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces 374 | # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1300.md 375 | # - Delegates 376 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces#names-of-common-types 377 | # - Constructors, Properties, Events, Methods 378 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-type-members 379 | dotnet_naming_symbols.element_group.applicable_kinds = namespace, class, enum, struct, delegate, event, method, property 380 | dotnet_naming_rule.element_rule.symbols = element_group 381 | dotnet_naming_rule.element_rule.style = pascal_case_style 382 | dotnet_naming_rule.element_rule.severity = warning 383 | 384 | # Interfaces use PascalCase and are prefixed with uppercase 'I' 385 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces 386 | dotnet_naming_symbols.interface_group.applicable_kinds = interface 387 | dotnet_naming_rule.interface_rule.symbols = interface_group 388 | dotnet_naming_rule.interface_rule.style = prefix_interface_with_i_style 389 | dotnet_naming_rule.interface_rule.severity = warning 390 | 391 | # Generics Type Parameters use PascalCase and are prefixed with uppercase 'T' 392 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/names-of-classes-structs-and-interfaces 393 | dotnet_naming_symbols.type_parameter_group.applicable_kinds = type_parameter 394 | dotnet_naming_rule.type_parameter_rule.symbols = type_parameter_group 395 | dotnet_naming_rule.type_parameter_rule.style = prefix_type_parameters_with_t_style 396 | dotnet_naming_rule.type_parameter_rule.severity = warning 397 | 398 | # Function parameters use camelCase 399 | # https://docs.microsoft.com/dotnet/standard/design-guidelines/naming-parameters 400 | dotnet_naming_symbols.parameters_group.applicable_kinds = parameter 401 | dotnet_naming_rule.parameters_rule.symbols = parameters_group 402 | dotnet_naming_rule.parameters_rule.style = camel_case_style 403 | dotnet_naming_rule.parameters_rule.severity = warning --------------------------------------------------------------------------------