DEV Community

Kurt Feeley for AWS Community Builders

Posted on • Edited on

Three Steps to Create a .NET AWS Lambda Function with an HTTPS Endpoint

AWS Lambda, which has often been credited as changing the way that we think about software and how we architect software, arrived in 2015 with much fanfare. Years later, Lambda's use continues to grow and AWS is still adding features.

If there had been one complaint by software developers, engineers, architects and the like, it is the one obvious missing feature -- a URL that could be assigned directly to an AWS Lambda function. Now, let's be honest, AWS API Gateway integrates with AWS Lambda and the process of integration is pretty straightforward. But, wouldn't it be nice to check a box in the AWS console and have a URL assigned to your Lambda function? Well, the wait is over, because that's exactly the feature that AWS recently released for Lambda.

Image description

Photo by Bonnie Kittle on Unsplash

The Solution

In this tutorial, we will build a simple .NET Lambda function that will be invoked from a URL. When invoked, the Lambda function will read any query string parameters in the URL and return a JSON array of the query string parameter values. In addition, we will create the AWS Lambda function, the Lambda function URL, the Lambda function execution role, and the supporting policies using the the AWS CLI.

Prerequisites

To complete this tutorial, you will need the .NET CLI which is included in the .NET 6 SDK. In addition, you will need to download the AWS CLI and configure your environment. You will also need to create an IAM user with programmatic access to AWS Lambda and IAM with the appropriate permissions to create and modify Lambda functions, create Lambda function URLs, create IAM roles and IAM policies.

Warning: some AWS services may have fees associated with them.

This tutorial was developed using Ubuntu 20.04, AWS CLI v2, .NET 6 SDK and Visual Studio Code 1.66.2. Some commands/constructs may very across systems.


"To create a function, you need a deployment package and an execution role." — docs.aws.amazon.com

1) Creating a Lambda Deployment Package

 

Developing a .NET AWS Lambda Function

To keep our Lambda function lean, we will start with a .NET class library. We can create the .NET class library with the following command:

$ dotnet new classlib -n LambdaWithUrl
Enter fullscreen mode Exit fullscreen mode

With the .NET class library created, let's change the directory to the newly created project folder, LambdaWithUrl and add the package dependencies like so:

$ dotnet add package Amazon.Lambda.APIGatewayEvents
Enter fullscreen mode Exit fullscreen mode
$ dotnet add package Amazon.Lambda.Serialization.Json
Enter fullscreen mode Exit fullscreen mode
$ dotnet add package Amazon.Lambda.Core
Enter fullscreen mode Exit fullscreen mode
$ dotnet add package AWSSDK.Lambda
Enter fullscreen mode Exit fullscreen mode

Ok, now that we have the bones of the Lambda function in place, let’s get into the code. For this tutorial, the code will be very concise.

We are going to create one class named, “Handler”, that has one method named, “Handle”. When the Lambda function is invoked, the Handle method will be called and it will process the data that is passed in from AWS Lambda. Since we are going to be invoking this Lambda via a URL, the method parameter type of the Handle method will be APIGatewayProxyRequest. To get an idea of the data that can be processed by the Lambda function, checkout an example JSON Payload or the C# APIGatewayProxyRequest class.

The Lambda function processing logic is simple in this tutorial. Essentially, when this Lambda function is invoked, the query string values will be plucked out and returned. Consumers of this Lambda function’s URL will receive a JSON array of strings containing the values from the query string parameters that were used to invoke the function.

Here’s the Handler class in its entirety.

using Amazon.Lambda.Core;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Serialization.Json;

namespace LambdaWithUrl;

public class Handler
{
    [LambdaSerializer(typeof(JsonSerializer))]
    public IEnumerable<String> Handle(APIGatewayProxyRequest apiGatewayProxyRequest)
    {
        return apiGatewayProxyRequest?.QueryStringParameters?.Values ?? new String[0];
    }
}
Enter fullscreen mode Exit fullscreen mode

That's it for the coding of our simple .NET AWS Lambda function.

Packaging the .NET AWS Lambda Function

For this tutorial, we will create a zip file deployment package of our .NET Lambda function.

The first step is to publish the .NET application using the following .NET CLI command. Notice the MSBuild GenerateRuntimeConfigurationFiles parameter. Setting GenerateRuntimeConfigurationFiles to true will instruct the .NET CLI to generate the (appname).runtimeconfig.json file that AWS Lambda requires.

$ dotnet publish \
   -c Release \
   -o lambda \
   /p:GenerateRuntimeConfigurationFiles=true
Enter fullscreen mode Exit fullscreen mode

Let’s change the directory to the “lambda” directory and zip all the directory’s contents with the following command. There are many options to zip files across Windows, Linux and macOS. Here you will see the command that was used in the Ubuntu environment. Whichever option you choose, make sure you zip the contents of the folder and not to include the folder in the zip file. Also notice that the lambda.zip file is placed in the LambdaWithUrl directory, which is important for a forthcoming step.

$ zip ../lambda.zip *
Enter fullscreen mode Exit fullscreen mode

That’s it, our AWS Lambda function is packaged and ready to be uploaded.

2) Set Permissions

 

Create the Lambda Function Execution Role

With the deployment package set to go, we can turn our attention to the execution role.

The execution role has two policies. The trust policy defines what principal can use or assume the role. The second policy defines the AWS services and resources in which the role has access to.

Let’s change the directory back to the project directory (LambdaWithUrl) and create a file named trust-policy.json with the following content.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Let’s use the following command to create the execution role, using the trust-policy.json file to create the trust policy.

$ aws iam create-role \
   --role-name lambda-with-url-execution-role \
   --assume-role-policy-document file://trust-policy.json
Enter fullscreen mode Exit fullscreen mode

With the role created, let’s define the permissions for the Lambda function. You could create your own policy and attach it, but for this tutorial we’ll attach the AWS AWSLambdaBasicExecutionRole managed policy. The AWSLambdaBasicExecutionRole simply will grant the Lambda function permission to create logs in Amazon CloudWatch.

Let’s use the following command to attach the AWSLambdaBasicExecutionRole policy.

$ aws iam attach-role-policy \
   --role-name lambda-with-url-execution-role \
   --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Enter fullscreen mode Exit fullscreen mode

And, with that, the Lambda function execution role is complete.

3) Configure the Lambda Function with the CLI

 

Create the .NET Lambda Function

With the Lambda function execution role completed and the deployment package ready to be uploaded, let’s create the Lambda function using the AWS CLI with the command below, replacing aws-account-number with your AWS account number.

$ aws lambda create-function  \
   --function-name lambda-with-url  \
   --runtime dotnet6  \
   --handler LambdaWithUrl::LambdaWithUrl.Handler::Handle  \
   --description lambda-function-with-url  \
   --zip-file fileb://lambda.zip  \
   --role arn:aws:iam::(aws-account-number):role/lambda-with-url-execution-role
Enter fullscreen mode Exit fullscreen mode

When completed, you should get a response with a JSON object with elements of FunctionName, FunctionArn, Runtime, etc.

Create the Lambda Function URL

The last step is to create a URL for the Lambda function. This can be done in two parts. Note: for this tutorial we allow public access and set function-url-auth-type to NONE. Scrutinize your security needs and set the URL permissions accordingly.

First, we need to create the Lambda URL and we can do so with this command:

$ aws lambda create-function-url-config  \
   --function-name lambda-with-url  \
   --auth-type NONE
Enter fullscreen mode Exit fullscreen mode

When completed, you should get a response with a JSON object with elements of FunctionUrl, FunctionArn, AuthType, etc.

Record the FunctionUrl for testing.

Finally, we need to set permissions in order to access the URL.

$ aws lambda add-permission  \
   --function-name lambda-with-url  \
   --statement-id FunctionURLAllowPublicAccess  \
   --action lambda:InvokeFunctionUrl  \
   --principal "*"  \
   --function-url-auth-type NONE
Enter fullscreen mode Exit fullscreen mode

When completed, you should get a response with a JSON object with the element of Statement.

OK, the Lambda function has been created along with the associated URL. The next step is to give the .NET Lambda function a test using its URL.

Testing the .NET AWS Lambda Function

Open a browser and browse to the Lambda URL that you recorded earlier. You should see an empty JSON array — [ ]. Append the following to the end of the URL and hit enter:

?param1=value1&param2=value2

Once the page loads, you should see the following response.

[
   "value1",
   "value2"
]
Enter fullscreen mode Exit fullscreen mode

Summary

We have concluded this tutorial where you have learned how to build a .NET Lambda function with an associated URL. You also learned how to create an IAM role and attach an IAM policy using the AWS CLI.

*** Don't forget to remove any unwanted AWS resources that were created for this tutorial ***

Top comments (0)