Martin Burcombe

Websites :: IT Services :: IT Training

My first C# based, AWS Lambda driven, API – Part 1

Categories: C#, CodeBuild, Lambda

So today I got my first C# based, AWS Lambda driven, API working in AWS. I also managed to set up automated deployment for it entirely within AWS.

 

This is something I have been aiming to do for a while now, but had stumbled with the automated build process. But today I saw a ‘Whats New’ announcement from AWS: ‘Announcing .NET Core Support for AWS CodeBuild and AWS CodeStar‘. This inspired me to revisit what I wanted to do and spurred me to get this working.

 

So, I began by putting together a new Visual Studio solution using the AWS Lambda template:
 
New Lambda Project

 

Its pretty simple as this is intended more just to get the process working than to be really useful as an API. As such, the API will return a list of authors. Later on I will build this out to be database driven, but for now its all static code. The project initially contains a model for ‘Authors’:

 


namespace BookyStuff_Lambda_Authors
{
  public class Author
  {
    public int AuthorID { get; set; }
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    public string LastName { get; set; }
  }
}

 

and the lambda function itself:

 


using Amazon.Lambda.Core;
using Amazon.Lambda.Serialization.Json;
using System.Collections.Generic;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace BookyStuff_Lambda_Authors
{
  public class Function
  {
    [LambdaSerializer(typeof(JsonSerializer))]
    public List GetAuthors()
    {
      List resultRows = new List();
      resultRows.Add(new Author { AuthorID = 1, FirstName = "Peter", MiddleName = "F", LastName = "Hamilton" });
      resultRows.Add(new Author { AuthorID = 2, FirstName = "David", MiddleName = "", LastName = "Gemmell" });
      resultRows.Add(new Author { AuthorID = 3, FirstName = "Guy", MiddleName = "Gavriel", LastName = "Kay" });
      resultRows.Add(new Author { AuthorID = 4, FirstName = "Stephen", LastName = "Baxter" });
      resultRows.Add(new Author { AuthorID = 5, FirstName = "Stephen", MiddleName = "R", LastName = "Donaldson" });
      return resultRows;
      }
  }
}

 

The project structure looks like this:
 
Lambda C# Project

 

I then made sure my solution was committed to a GIT repo on AWS CodeCommit. This is where the build process will get the source code to build. Pushes the repo will also initiate the automated build process via AWS CodePipeline later on as well.

 

So at this point, I started looking at the new documentation for automating .NET Core builds on AWS. This gave me starting point for putting together a buildspec.yml file as part of my solution, which is required to drive the build in AWS CodeBuild. I added the buildspec.yml file at the solution level rather than the project level as follows:

 

Lambda C# Solution

 

I went through a number of iterations of the buildspec.yml file in the process of getting the build working. This was mainly trying to understand where artifacts were put, and how to zip them up so they would be exported to an S3 bucket in the way I wanted. I hope I have set this up so that I can export multiple Lambda projects in one build process, to multiple zip files so they can be installed separately. I’m not sure I have this right yet, but the commands I have work fine for what I am doing so far, though there are simpler ways to get it working for a single lambda.

 

The other issue that caught me out and took a while to resolve was indentation. I initially had the ‘artifacts’ line indented by two spaces (which each of the following lines also indented by 2 extra spaces each). This resulted in a number of ‘No artifacts Found’ errors. Once I realised that indentation was important and fixed it, the build artifacts started getting exported to S3.

 

So, my final iteration of the buildspec.yml file (for today at least) looks like this:

 


version: 0.2
 
phases:
  build:
    commands:
      - dotnet restore
      - dotnet publish BookyStuff_Lambda_Authors/BookyStuff_Lambda_Authors.csproj -c Release -o bin/Release/netcoreapp1.0/publish/BookyStuff_Lambda_Authors
      - cd BookyStuff_Lambda_Authors/bin/Release/netcoreapp1.0/publish/BookyStuff_Lambda_Authors
      - zip ../../../../../../Artifacts/BookyStuff_Lambda_Authors.zip *
      - cd ../../../../../..
artifacts:
  files:
    - Artifacts/BookyStuff_Lambda_Authors.zip
  discard-paths: yes

 

At this point, I would like to credit Max Horstmann’s article ‘Continuous Integration: C# to AWS Lambda‘ which helped me greatly with the buildspec.yml file, and the build process in general.

 

With the solution committed and pushed to CodeCommit, I set up the automated build.

 

Firstly, I created a bucket in S3 to hold the artifacts from the build. Nothing special there, except I added versioning so that I may have access to previous builds if required. I don’t think thins is strictly necessary though.

 

Next, I created a new build. This is pretty straightforward now that there is a .NET image managed by AWS. So the settings I chose are shown in the next couple of images:

 

CodeBuild-Part 1

 

CodeBuild-Part 2

 

When I first set up this build and tested it, I had some successes, but no artifacts, then as I tried to fix this I had a few failures. But once I got the buildspec.yml set up as described above, the builds started working and the artifacts (a zip of the source code that will be imported to the lambda) began appearing in the S3 bucket.

 

Next IU automated the build. I set up a new pipeline in AWS CodePipeline. This begins by having a Source step. This is set to the Master branch of CodeCommit repo I set up earlier (thats the only branch I have at the moment). This then pipes to a Build step which uses the build I have just set up in CodeBuild. So the pipeline looks like this:

 

CodePipeline

 

The source step is configured as follows:

 

CodePipeline - Source

 

And the Build step is set up as follows:

 

CodePipeline - Build

 

So now, each time I push a commit to the repo, I wait a couple of minutes and I have a new build package (ie. article zip file) in S3, ready to update my Lambda.

 

My next step is to add a step tot he pipeline to automate the update of the Lambda. I think this will require a Cloudformation template as there is no way to update the Lambda directly using AWS CodeDeploy. Failing that, I can use the AWS CLI to update the Lambda (Max had this happening in the buildspec.yml file, so wouldn’t even need to push artifacts to S3, but I would prefer to have a separate step in CodePipeline). I also want to add some unit tests to the solution, and a test step in the pipeline. I do have the API working, via CloudFront, but will talk about this more in a later blog entry.

0 Comments

Recent Comments