DEV Community

Bastian
Bastian

Posted on

Deploy a .NET Core Web API with AWS Lambda and the serverless framework

One of the cool things you can do with lambdas triggered by API Gateway is that you can simply let your code handle the routing. This should work for all serverless stacks and I have already used it for nodejs (check out this dev.to article explaining how this works for nodejs).

Of course you could also go and define a lot of separate functions and create a new API Gateway Resource/Method for each. What I really like about running your entire application instead of function by function is the fact that you can firstly run existing apps without a huge change. You can actually simply run the same app in the lambda run time, in a container or by hitting F5...

Secondly you will not have to reinvent the wheel when it comes to standards you already have established in your .net core Web APIs e.g. health check endpoints, logging standards and all the other middleware you really appreciate.

There are already a bunch of tutorials out there that help you set up your .net core Web API with lambda. They do however use Visual Studio templates or .net core cli templates. The problem for me with this templates is that they don't rely on one tool that is a must for me when it comes to serverless - the serverless framework. So in this post I would like to explain how to set up a .net Core Web API on lambda with the serverless framework. This is not very complicated, but I will not go into detail about things covered in other tutorials.

The final result will be something like this:

api_gw_lambda_aspnetcore

Prerequisites

You should have a couple of things set up already

Creating the API

Create a new folder you want your code to reside in and run:

dotnet new webapi
Enter fullscreen mode Exit fullscreen mode

You can test that it works locally by running the following commands and then opening http://localhost:5000/api/values:

dotnet restore
dotnet run
Enter fullscreen mode Exit fullscreen mode

Adding the serverless framework to it

Add a file called serverless.yml with the following content:

service: exampleservice

provider:
  name: aws
  runtime: dotnetcore2.1
  region: eu-west-1

package:
  artifact: bin/release/netcoreapp2.1/deploy-package.zip

functions:
  api:
    handler: exampleservice::exampleservice.LambdaEntryPoint::FunctionHandlerAsync
    events:
     - http:
         path: /{proxy+}
         method: ANY
Enter fullscreen mode Exit fullscreen mode

If you already are using the serverless framework you should be familiar with most of the file's content.
We are adding an API Gateway that has a wildcard path => {proxy+} and the handler points to a not yet existing function.
(Change the region to something that makes sense for you).

Adding additional dependencies

Open your csproj file and change it to something like this (don't forget to run dotnet restore afterwards):

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.App" Version="2.1.0" />
    <PackageReference Include="Amazon.Lambda.Core" Version="1.0.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.Json" Version="1.4.0" />
    <PackageReference Include="Amazon.Lambda.AspNetCoreServer" Version="2.1.0" />
  </ItemGroup>

</Project>  
Enter fullscreen mode Exit fullscreen mode

! It is important to explicitly point to a specific version of Microsoft.AspNetCore.App. The dotnet new webapi command will not do that by default.

Add the lambda entry point (handler)

Additionally to your Program.cs file which handles the initialization of your app when you start it locally we need to add an handler for the lambda to hook into. Check the serverless.yml file we created earlier for reference. The handler in the serverless.yml has to be exactly correct -> {assemblyname}::{namespace}.{class}::FunctionHandlerAsync. Create a file called LambdaEntryPoint.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using System.IO;

namespace exampleservice
{
    public class LambdaEntryPoint : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
    {
        protected override void Init(IWebHostBuilder builder)
        {
            builder
                .UseStartup<Startup>();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Add build/package scripts for your application

Before you can package your lambda you will have to install the dotnet-lambda cli tool:

dotnet tool install --global Amazon.Lambda.Tools --version 3.0.1
Enter fullscreen mode Exit fullscreen mode

for windows systems add a file called build.ps1 :

dotnet restore
dotnet lambda package --configuration release --framework netcoreapp2.1 --output-package bin/release/netcoreapp2.1/deploy-package.zip
Enter fullscreen mode Exit fullscreen mode

if you run this in debian (e.g. docker image microsoft/dotnet) add build.sh :

#!/bin/bash

#install zip on debian OS, since microsoft/dotnet container doesn't have zip by default
if [ -f /etc/debian_version ]
then
  apt -qq update
  apt -qq -y install zip
fi

dotnet restore
dotnet lambda package --configuration release --framework netcoreapp2.1 --output-package bin/release/netcoreapp2.1/deploy-package.zip
Enter fullscreen mode Exit fullscreen mode

Test the build by running the build script for your environment e.g.

.\build.ps1
Enter fullscreen mode Exit fullscreen mode

! You will have to run this every time your code changes. Perfectly fine when you run this as part of a CI/CD pipe since you will have to execute that script anyways, but easy to forget if you just play around with it and deploy from your machine.

Publish your application!

This should be it! It is time to deploy the app. This assumes that you have followed the serverless install instructions and set up your AWS account (may mean that you have to adjust your serverless.yml file to make that work for you):

serverless deploy -v
Enter fullscreen mode Exit fullscreen mode

This should result in something like this:

serverless-log

Copy the highlighted link, replace {proxy+} with api/values and you should get the same result as before! Congrats!

This was a quick write up! If you miss information for some of the steps please add a comment so I can be more clear.

The example repository can be found here: https://github.com/schwamster/lambda_webapi_serverless

Top comments (5)

Collapse
 
neetika123 profile image
neetika123

hi Bastian,
First of all nice article,

  1. I tried the same approach and steps but not getting the output.
  2. I didn't get this 'FunctionHandlerAsync' is this inbuilt defined function via dotnet handler: exampleservice::exampleservice.LambdaEntryPoint::FunctionHandlerAsync
  3. want few explanation on deployment process. If you have to use CI/CD process then steps would be same or different ?
Collapse
 
schwamster profile image
Bastian

thanks, glad you enjoyed it.

2) Did you add the LambdaEntryPoint.cs file as described in "Add the lambda entry point (handler)"? In that file you derrive from the class "APIGatewayProxyFunction" that does contain the FunctionHandlerAsync => github.com/aws/aws-lambda-dotnet/b... This class is part of the nuget package "Amazon.Lambda.AspNetCoreServer" that you added in the section before

3) yes there would be no real difference. you would build and deploy. Optimally you have a build image prepared that has all of the necessary tools, .net core sdk, serverless framework, lambda tools. You might want to pass some parameters to the serverless framework if you for example want to deploy to different environments (serverless.com/framework/docs/prov...)

Hope this helps

Collapse
 
sshanzel profile image
Hansel Solevilla

Truly helpful, clear and concise.

Collapse
 
beenacelin profile image
BeenaCelin • Edited

Hi Bastion,

Thanks for the detailed article.
Is there any testing done for Security - Authentication/Authorization integration by using MS Authentication Library.
Thanks.

Collapse
 
dasarisrikanth profile image
srikanth dasari

dude i owe you coffee for this....thanks

i was having subtle confusion between lambda function vs server-less application...but got some idea now...