Create a .NET AWS Lambda Function with an HTTPS Endpoint

Get all the code on GitHub.

AWS Lambda, the popular AWS service, has been the solution behind many microservices. Some even argue that AWS Lambda enabled the microservice trend over the last five to seven years. And, the serverless/AWS Lambda trend does not show any signs of slowing down.

Even with its popularity, there was always one missing ingredient, a URL that could directly invoke the AWS Lambda function. Some could argue that this could be accomplished through the use of AWS API Gateway along with AWS Lambda. Although, what if you don’t need everything that AWS API Gateway gives you? Or, what if you don’t want or need the hassle of AWS API Gateway? And, maybe, you’re just looking for a checkbox in the AWS Console for the Lambda configuration that enables a URL for the function? If this sounds like you, then the wait is over, because that’s just the feature that AWS recently announced for Lambda.

Photo by Bill Fairs 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 list 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.

Remember, for any example solution from AWS with .NET, we focus on the code that exemplifies the problem we are trying to solve. We don’t include logging, input validation, exception handling, etc., and we embed the configuration data within classes instead of using environment variables, configuration files, key/value stores and the like. These items should not be skipped for proper solutions.

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.

Our Dev Environment

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.

Developing a .NET AWS Lambda Function

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

$ dotnet new classlib -n LambdaWithUrl

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

$ dotnet add package Amazon.Lambda.APIGatewayEvents
$ dotnet add package Amazon.Lambda.Serialization.Json
$ dotnet add package Amazon.Lambda.Core
$ dotnet add package AWSSDK.Lambda

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. Because 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];
}
}
view raw Handler.cs hosted with ❤ by GitHub

That’s it for our .NET Lambda function code.

“To create a function, you need a deployment package and an execution role .”

docs.aws.amazon.com

Packaging a .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. Note 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

Let’s change the directory to the “lambda” directory and zip all the directory’s contents with the following command.

$ zip ../lambda.zip *

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

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"
}
]
}

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

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

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

Create the .NET Lambda Function with AWS CLI

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.

$ 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

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

Create the Lambda Function URL with AWS CLI

The last step is to create a URL for the Lambda function. This can be done in two parts.

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

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

Record the FunctionUrl for testing.

Finally, we need to set permissions in order to access the URL. 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.

$ aws lambda add-permission ––function-name lambda-with-url ––statement-id FunctionURLAllowPublicAccess ––action lambda:InvokeFunctionUrl ––principal “*” ––function-url-auth-type NONE

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

OK, the Lambda function has been created along with an 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. 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"
]

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.

Challenges

Now that you have a working solution, let’s take things a little further…

  • Add logic in the Handle method of the Handler class to validate the presence of QueryStringParameters.
  • Use the AWS CLI to list Lambda functions.
  • Use the AWS Console to view the newly created Lambda function.
  • Use the AWS CLI to remove all of the resources that were created in this tutorial.

Get all the code on GitHub.

Want to know more about the tech in this tutorial?  Checkout these resources:

.NET CLI

AWS CLI 

Configuring the AWS CLI

AWS Lambda

AWS Lambda CLI