Skip to content
Article

Deploying a .NET Core API to AWS Lambda & API Gateway using Bitbucket

After a transition to Bitbucket for our repository hosting last year, we’ve been setting up more and more CI/CD using Bitbucket Pipelines. I recently converted a .NET Core API project that was deploying to an auto-scaling group of EC2s into a project that could be deployed in AWS Lambda behind API Gateway using Bitbucket. The web project that consumes this API is written in Angular.

As a shop that leverages automated deployments in multiple environments, I found documentation on the web to be in short supply other than very basic “deploy using VS Studio” articles.

As part of updating the API project to Lambda, I did make my LambdaEntryPoint reference APIGatewayHttpApiV2ProxyFunction and the serverless template event of type HttpApi. A guide to these updates can found here: https://aws.amazon.com/blogs/developer/one-month-update-to-net-core-3-1-lambda/

In this post, I provide some snippets of YAML code which I found out in the world that didn’t work, and also what ultimately did.

Jump to What Worked

What Didn’t Work

Wow did I get tired of seeing this.

aws-sam-deploy

caches:
  - dotnetcore
steps:
  - export PROJECT_NAME=this-dotnet-project
  - dotnet restore
  - dotnet build $PROJECT_NAME
  - pipe: atlassian/aws-sam-deploy:1.5.0

When trying to use the aws-sam-deploy pipe, I wasn’t able to leverage enough options or get the API to run the .NET code successfully. The API Gateway endpoint was running and hitting Lambda, but I was getting system errors I just couldn’t resolve.

Using project appsettings files

Since appsettings.json files contains secrets, we don’t check them into the repo. At some point I was receiving these errors, and I realized that the appsettings files weren’t getting deployed correctly.

run_dotnet(dotnet_path, &args) failed

Could not find the required 'this-dotnet-project.deps.json'. This file should be present at the root of the deployment package.: LambdaException

We ended up injecting the appsettings content using the AWS Parameter Store with aws ssm get-parameter.

dotnet publish, zip, and aws-lambda-deploy

- apt-get update && apt-get install --yes zip
- dotnet restore
- dotnet publish ${API_PROJECT_NAME} --output "./publish"  --framework "netcoreapp3.1" /p:GenerateRuntimeConfigurationFiles=true --runtime linux-x64 --self-contained false
- curl -o /bin/jp -L https://github.com/jmespath/jp/releases/download/0.1.3/jp-linux-amd64 && chmod a+x /bin/jp
- aws ssm get-parameter --name "/this-project/api/dev/appsettings" --with-decryption --region us-east-1 | /bin/jp -u "Parameter.Value" | base64 -d > ./publish/appsettings.json
- zip -r -j package.zip publish/*         
- pipe: atlassian/aws-lambda-deploy:1.5.0
  variables:
     AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID}
     AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
     AWS_DEFAULT_REGION: ${AWS_REGION}
     FUNCTION_NAME: "this-dotnet-project-AspNetCoreFunction-LZj5pbvV0GRT"
     COMMAND: "update"
     ZIP_FILE: "$BITBUCKET_CLONE_DIR/package.zip"

We have some single Lambda functions (not behind API Gateway) that use this method for deploying. It works great. I tried using this method pushing to a function that was built with a stack published via VS Studio. No luck. It’s possible there was a problem with the stack that was built, but I think this package wasn’t exactly right.

What Works

Finally!

The following is the pipeline for a single branch, our develop branch. I haven’t yet refactored using template steps, but this is easier to read through for this article anyway.

I have scrubbed the contents of this YAML, but the repo contains:

  • Root (.sln file)
    • .Net Core API project directory (named this-dotnet-project here)
    • Angular web project directory (named this-web-project here)
pipelines:  
  branches:
    develop:
      - step:
          name: API (.Net Core) Build & Deploy 
          image: mcr.microsoft.com/dotnet/core/sdk:3.1
          deployment: Develop
          script:
          - apt-get update && apt-get install -y zip && apt-get install -y awscli
          - dotnet tool install -g Amazon.Lambda.Tools
          - export PATH="$PATH:/root/.dotnet/tools"
          - curl -o /bin/jp -L https://github.com/jmespath/jp/releases/download/0.1.3/jp-linux-amd64 && chmod a+x /bin/jp
          - aws ssm get-parameter --name "/this-project/api/dev/appsettings" --with-decryption --region us-east-1 | /bin/jp -u "Parameter.Value" | base64 -d > ./this-dotnet-project/appsettings.json
          - cd this-dotnet-project/
          - dotnet lambda deploy-serverless --aws-access-key-id ${AWS_ACCESS_KEY_ID} --aws-secret-key ${AWS_SECRET_ACCESS_KEY} --region ${AWS_REGION} --configuration "Development" --framework "netcoreapp3.1" --runtime linux-x64 --s3-bucket $API_S3_BUCKET --stack-name $API_STACK_NAME --stack-wait true
      - step:
          name: Web (Angular) Build
          image: atlassian/default-image:2
          caches:
          - node
          script:
	      - cd this-web-project #The angular project is currently in a subfolder in the same repo
          - nvm install 12
          - nvm use 12
          - npm install @angular/cli
          - npm run build:dev
          artifacts: # defining the artifacts to be passed to each future step.
          - dist/**
      - step:
          name: Web (Angular) Deploy
          script:
          - pipe: atlassian/aws-s3-deploy:0.5.0
            variables:
              AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} 
              AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY}
              AWS_DEFAULT_REGION: ${AWS_REGION}
              S3_BUCKET: ${WEB_S3_BUCKET_DEV}
              LOCAL_PATH: "this-web-project/dist/this-project-output-path/"

apt-get install and dotnet tool install

Items that were quickly apparent as missing before adding them, more of a “duh” leaving them out when trying so many things.

dotnet lambda deploy-serverless

This was the big command that mostly got things working. I finally found this is effectively what’s happening when you deploy the API project from VS Studio.

–stack-wait true

In Bitbucket, without this, the build shows as successful when the stack build is kicked off. By adding this flag, bitbucket will wait for the full build or update before continuing.

capabilities covered
Learning Management Systems DevOps WordPress Custom PHP Applications Amazon Web Services Application Architecture Custom .NET Applications

The Atlantic BT Manifesto

The Ultimate Guide To Planning A Complex Web Project

Insights

Atlantic BT's Insights

We’re sharing the latest concepts in tech, design, and software development. Learn more about our findings.

Questions & Answers

What is the best web development framework?
Many people commonly ask “what is a framework in web development?” Web development frameworks can easily be confused with web development tools, languages, or parts of the web development stack (like PHP, Ruby, or Javascript).
Learn More about What is the best web development framework?
What is the best programming language for web development?
If there was one “best” programming language, then everything else would be obsolete. The reality is that there are so many different programming languages because there is no “best” language for any situation.
Learn More about What is the best programming language for web development?
How much does web development cost?
Web development can vary from a few hundred to millions of dollars depending on what is needed. You may simply need some changes to something that already exists, or you'd like to build a large or complex application.
Learn More about How much does web development cost?
What is web design and development?
People often lump web design and development together, so what's the difference? As the Internet has evolved, the skills required to produce a high quality website or web application have changed.
Learn More about What is web design and development?
What is JavaScript used for in web development?
Historically speaking, JavaScript was only commonly but sparingly used in web development. The multiple browsers in use at the time each supported different versions of JavaScript and were slow to render more complex Javascript.
Learn More about What is JavaScript used for in web development?
What is React web development?
React is a popular JavaScript library. It is primarily used for building interactive user interfaces (UI).
Learn More about What is React web development?
What is PHP web development?
PHP is a back end language primarily used for custom applications, content management systems (such as Wordpress), eCommerce engines (such as Magento), or even massive sites like Facebook.
Learn More about What is PHP web development?