Launch a C# .NET Core Lambda function — step by step

So, you’ve heard about serverless in AWS and you’re asking yourself how do I create one? Where to start?

There are many blogs, guides and online videos that provide information and guidance, which is magnificent. We live in an era with abundance of information. However, although the information is somewhere out there, I find myself struggling to find the exact guide that shares the steps, possible problems, errors and solutions. It has led me to publish this post.

So yes, this post will join the other thousands of online posts about serverless, but with the focus on Lambda function based on C#.NET Core using Visual Studio, as Amazon announced just recently that they have started supporting C# using the .NET Core 2.0 (January 2018).

If your background is C# and you are sticking to .NET Core — you are lucky.

TL;DR

The gist of this post:

  • Defining a Lambda function and connecting it to API Gateway
  • Developing a simple C# Lambda function and publishing it by using AWS toolkit in Visual Studio
  • Setting the relevant permissions using IAM for publishing and running AWS Lambda function
  • Invoking the function via HTTP GET request
  • The last (and most important): having fun throughout the whole process and learning how to overcome common problems and errors

Enjoy!


A really short intro to serverless

A short recitation for those who are not familiar with the serverless concept: serverless aims to focus on the functionality without worrying about the host of the service. The cloud vendor, in this case AWS, provides the host infrastructure (hardware, RAM, storage, network, availability) whilst the developer is in charge of the functionality. Meaning, all the overhead of setting a VM with OS, defining the storage and RAM is handled by AWS, leaving the developer to focus purely on the functionality.

In addition, the developer sets the required resources for his or her service. The cloud vendor allows you to scale-up and scale-out automatically based on the specifications and the required resources (mostly the utilization and availability).

One last thing, serverless is event-triggered. It has to be invoked by a trigger. so it runs based on demand.

AWS has branded its serverless computation solution under the name Lambda.

Define a serverless function in AWS

To begin, obviously you should have an active AWS account, which I assume you already have. If not, please refer to this guide and open an AWS account.

Image 1: Select Lambda Services

The next step is to create a serverless service. Under Services, search for Lambda services. Once the screen is opened, click on the “Create Function” button. For simplicity purposes, choose “Author from scratch” and set the function’s name. To be consistent with the example in this post, the chosen name is “DoorKnock”.

The next important input is the role. If you have a previous defined role, you can leverage on it. However, it is much cleaner to create a new dedicated role for this new function. By doing that, you can assure that the relevant permissions are granted properly and are segregated from your other AWS resources managed by you. Once you click on “Create function”, the next screen is the function’s configuration screen. You can see the screen has two tabs, Configuration and Monitoring. Our main operation will be done in the Configuration screen.

Configure the API Gateway

Image 2: Selecting API Gateway

The whole concept of a serverless function is execution on demand. Therefore, the trigger for activating a serverless function is an external source. AWS provides a list of triggers. For demonstration purposes, I chose the simplest, which is API Gateway. After selecting the API Gateway option, its configuration appears below. In the configuration screen, choose “Create a new API” and set its name. The name of my function is “DoorKnock”, so staying with the same lexicon, I chose the gateway’s name to be “DoorStep”.

Image 3: Set an API Gateway deployment

AWS will then request to set the Deployment stage’s name. Since each API can have more than one deployment, to distinguish between them we need to label each of them. In short, this name indicates the label of the API Gateway deployment. For this demo, the selected name is “Prod”.

After setting the essential values to the API Gateway and saving them, we continue to configure the gateway. It can be accessed by clicking the API Gateway link under our function definition or by accessing the API Gateway services from AWS main services dashboard.

Image 4: Connect the API Gateway resource to our Lambda function

The next step is to create a GET request and connect it to our Lambda function. After selecting the newly created API, in the Resources menu, click on the Actions →Create Method item. Let’s select GET and relate it to our “DoorKnock” Lambda function. By doing that, the GET request of this API Gateway invokes our “DoorKnock” function.

To recap so far, we have configured a function which is triggered by API call. We have yet to see the URL of the API and configure the request and response details. At this point, we’ve kept the default configuration. 
If you have reached to this stage, you are halfway through!
The next step is to fill in the logic of our function.

Develop a Lambda function in C#

At this stage, we have a Lambda function that is triggered by API Gateway, but without any real functionality. So, let’s define one.

Welcome to AWS Visual Studio toolkit

First, download and install the AWS Visual Studio Toolkit https://aws.amazon.com/visualstudio.

Image 5: Setting AWS account

After restarting the Visual Studio (referred to as VS), a new explorer is born. Its genuine name is AWS Explorer. It is reachable via the View menu, or (Ctrl+K, A) if you like key shortcuts. To define a connection between the VS and your AWS account, you need to import the credentials of existing AWS users. This post will not dive into the IAM topic, but I will shortly mention that once you have an active AWS account, each of your profiles have unique keys. Those keys can be exported to a CSV file. Connecting the VS to AWS requires you to provide these credentials.

Develop our function, finally

Now, we are finally ready to pour some C# code into our function. Simply create a new project: File → New → Project →Visual C# →AWS Lambda →AWS Lambda Project (.NET Core). Once you’ve selected the project, VS will present several blueprints. For simplicity, let’s choose “Empty Function” and create the project. The project’s name I have chosen for this demo is “KnockIT”.

You might have noticed that VS presented two project types: AWS Lambda Project and AWS Serverless Application. What are the differences between them? Well, AWS Lambda Project is used for creating a project to develop an individual Lambda function, whilst AWS Serverless Application enables you to define more than just the function; it allows you to create multiple functions at one time with a serverless AWS CloudFormation template. For example, you can simultaneously create a database, add IAM roles and more.

Now we are finally ready for some coding. To make it simple, our function will return the current time (hour, minute, seconds).

Let’s create a simple method that returns a time in the format hh:mm:ss :

Simple C# method

This is a simple method, with the purpose to publish and expose it as a Lambda function. More complicated code and functionality is a good topic for other posts, once we have constructed a working example.

Upload the function to AWS

After compiling and testing the method, we are ready to deploy it. Right click on the C# project and select “Publish to AWS Lambda” and the following wizard will pop-up:

Image 6: Upload Lambda function

Select the account profile to execute the upload process. This account should have a proper permission set for executing the upload (don’t worry, we will address it later if this is not the case). The next important fields are the function’s name (in our example it’s “DoorKnock”) and the method to be executed, and then click next. If there are no problems and the connection to AWS has worked properly, the next screen should present the function’s execution role name and other execution parameters. However, there may be problems connecting to AWS, for instance, the chosen account did not have the right permissions to access Lambda resources or there was a problem with the function’s assigned role. In these cases, AWS will prompt you about the problem. To rectify it, I suggest you seek for a solution based on the error message. For more details about Lambda permissions model, click here. Anyway, these are not common errors.

Permissions issues and how to fix them

The next step is to click on the Upload button and wait. As the title of this paragraph implies, we will encounter a problem. An error will appear in wizard’s output control. The most common problem is about permission: “User: arn:aws:iam::<user_ID> is not authorized to perform: lambda:GetFunctionConfiguration on resource: arn:aws:lambda:<function_resource_ID>:function:DoorKnock”. Behind this error underlies the fact that the user account we have chosen was missing the relevant permissions to run the upload process.

To overcome this problem, grant the relevant permission to the user to upload the function. First, let’s obtain the function’s resource name (ARN). It can easily be found in the function’s management screen:

Image 7: Get the function’s ARN

The next step is to assign the permission to the user account. In order to make a clean and managed solution, let’s create a new policy: IAM →Policies →Create Policy. For simplicity, we will use the Visual editor tab (instead of JSON tab). Set the Service to Lambda, then select Read →GetFunctionConfiguration permission. Next, choose the specific resource, which is our function, by providing the function’s ARN (see image below).

Image 8: Provide the function’s ARN to the new policy

I’m keen about security aspects, and thus I prefer to assign only the minimum required permissions set. To ensure we do not grant more permissions than required, let’s select only the missing permission, which is GetFunctionConfiguration, instead of granting permission to All Lambda actions. Afterwards, review the policy, set its name (I chose DoorKnockFunctionAccess) and save it.

Now all we have to do is to attach the policy DoorKnockFunctionAccess to the user account we provided to AWS wizard (see image 6). It is simply done under the policy or user management screen.

Now let’s try to publish our function again. Ooopp… this time we encounter another variance, the same as the previous problem. The missing permission is UpdateFunctionCode. To save you time and to strive for a solution, I will reveal that there are two more essential missing policies: UpdateFunctionCode, InvokeFunction. So, in total, our policy DoorKnockFunctionAccess should contain only 3 policies: GetFunctionConfiguration, UpdateFunctionCode, InvokeFunction. Assign these actions to the policy and save it. No need to repeat the attach policy action again, as the policy is already attached. Now, let’s try to publish our function again. This time it should work 😉

Image 9: AWS explorer in VS

After a successful publishing, VS opens a panel that provides a direct access to the Lambda function configuration and its resources. It allows the developer to invoke the function and view the response, as well as access valuable function’s configuration parameters and logs.

This panel can be accessed from VS AWS explorer as well. An interesting field is the function’s handler name, which is KnockIT::KnockIT.Function::TheTimePlease. This name is followed by the convention of assembly::namespace.class-name::method-name.

A note for those who are interested to know more about the action behind the scenes: the VS AWS wizard has zipped the relevant files and uploaded them into the AWS function. The zipped file can be found under the C# project’s Release folder, for example: KnockIT\bin\Release\netcoreapp2.0\KnockIT.zip. The same process can be done manually or by using the ASW Lambda Functions console (under the section Function Code, there is a button to upload a zip file).

Testing our function

So, now we have a function with a simple logic. Let’s test it as a standalone function, before integrating it with API Gateway. There are some ways to execute the test:

  1. Using the VS: Follow image 9 above and click on the Invoke button. Upon a successful run, the function should return the expected result. You can also select Sample Input and simulate various inputs.
  2. Via AWS management screen: On the top of the Lambda function management screen, you can find a “Test” button. This functionality allows you to define a test event input value and indicate whether or not the test has passed or not.
  3. Using the API Gateway resource: Navigate to API Gateway resource (see image 4), select the GET method and click on the Test button (the one with the flash icon ⚡️).
In case the response is “Could not find the required ‘LambdaTest.deps.json’” or “Unable to find method ‘XXX’ in type ‘YYY’”, most likely the handler’s name is invalid. To ensure the handler’s name is correct, it should comply with the convention assembly::namespace.class-name::method-name (see image below).

Although our C# class can have more than one method, there is only one entry point. The handler parameter is the entry point for our Lambda function.

Image 10: Setting the Lambda active function

Exposing the Lambda function via HTTP

So, after verifying that the Lambda function is working properly, the final step is invoking it via HTTP request. The Gateway resource is already connected to the Lambda function, as we have tested before. So, the next step is exposing it via HTTP GET request.

Navigate to the API Gateway stage that was configured before (we named it “Prod”). After selecting the GET command, the URL appears above:

Image 11: API Gateway URL

If we open the URL in a browser, we expect to receive the same response: “The time is: XXX”. However, instead, the browser displays an unexpected response:

{"message": "Internal server error"}

To tackle this error, more logs are required. Configuring AWS logs is an easy task; just follow the simple instructions in this post.

In case you want to skip to the rectifying action — jump to the next chapter 👇

Once you have finished, the logs are accessible via CloudWatch →Logs →API-Gateway. Digging in the logs reveals the problem: “Execution failed due to configuration error: Malformed Lambda proxy response

Apparently, AWS Gateway expects a specific response format:

{ "isBase64Encoded": true|false, "statusCode": httpStatusCode, "headers": { "headerName": "headerValue", ... }, "body": "..." }

To fix that, changing our C# source code is required.

Changing the C# code to support API Gateway response format

Fortunately, and wisely, AWS has created an object that encapsulates the API Gateway response. All we have to do is import Amazon.Lambda.APIGatewayEvents NuGet package into our C# project and use the object APIGatewayProxyResponse as the return value of our method. See an example below:

AWS APIGatewayProxyResponse example

If you have managed to follow so far, you are an expert in publishing AWS Lambda functions with VS, so re-publish the function using VS AWS wizard. Once the process has been successfully completed, re-launch the URL. The expected result should be similar to the following (except the time of-course 🙂) :

Hello AWS Serverless! the time is: 09:37:03

By reaching to this point, you have made quite a big progress, starting from zero to a working Lambda function. Very good!
We still have not covered many features and capabilities. That was really the tip of the ice, but any journey starts with its first step!

What’s next?

After gaining a foothold in Lambda domain, the next step is to understand more about API Gateway input and output and how to use this knowledge to achieve better flexibility in implementing Lambda function. I cover this topic, as well as C# Lambda deployment parameters, in my other blog-post: “5 Useful Features of C# .NET Core Lambda function”.

Another important aspect, which wasn’t covered in this blog-post, is network. Our Lambda service was not associated with any network, however, AWS allows Lambda function to be hosted in a specific subnet. Follow these blog-posts to start your journey into the AWS Virtual Private Cloud world: VPC building blocks and a practical guide for building VPC with EC2 instances.

Wrap-up

If you are a coder in your soul, you must be familiar with that special feeling when things are working as you wished. I hope you felt it while walking through this post.

Thanks for reading! If you liked this, give it some love by pressing on the 👏 button! Feel free to comment and highlight.

Have fun and happy coding!