Hosting .NET 6 Web API with AWS Lambda – Truly Server less REST APIs

In this article, we will learn about hosting ASP.NET Core Web API with AWS Lambda in a rather simple-to-follow manner. It is going to be as simple as developing a .NET 6 Web API as you would normally do using Controllers or Minimal APIs, and running some CLI commands which will deploy your API as Lambda Function to AWS Lambda super fast!

As part of the “Server less Applications with AWS on .NET” series, in earlier articles, we learned about hosting AWS Lambdas and exposing them via Amazon API Gateways to achieve the same. With this article, we will be learning a simple way to get your ASP.NET Core Web API Hosted onto the AWS Infrastructure with AWS Lambda! In other words, we will be building a server less REST API with .NET 6 and deploying it to the AWS Infrastructure using AWS Lambdas.

When to Host ASP.NET Core Web API with AWS Lambda?

Choosing when and where to use what kind of Hosting Strategies is vital for your business and customer needs. This can also be the break or make decision in saving costs of your AWS services. Now that we understand the pros and cons of hosting web APIs into AWS Lambdas, let’s understand when to use this approach and when not to.

Hosting ASP.NET Core Web API is pretty cool for building a Web API that is not very crucial or not called very often. Always keep in mind that the response time of APIs hosted over AWS Lambda can be a bit longer, with the cold starts adding at least 1-2 additional seconds to the overall response times. Being serverless, it costs nothing when there are no incoming requests, and also it costs close to nothing even when there are requests coming in, thanks to the generous Free Tier of AWS!

The Free Tier provides you 1 Million free requests per month for AWS Lambda, forever! And after 1 Million Lambda requests per month, you will be charged like 0.20 USD for the next 1 Million requests, which is again very affordable! And if your application is hitting 1 Million requests a month, you would probably be running a pretty successful business as well.

And, as mentioned in the previous section, if you plan to deploy a complicated, large-scale .NET Web API to AWS Lambda, it’s probably not a good idea. A better approach would be to Dockerize the application and run it over AWS App Runner, ECS, EC2 or even deploy it into an Elastic Kubernetes Cluster of Amazon! As you see, the options you get while hosting ASP.NET Core to the AWS Infrastructure are pretty deep, and solely depend on the use case and purpose of your application! Let me know in the comments section below if you want me to write articles related to the other approaches to deploying an ASP.NET Core Web API to the AWS Infrastructure.

Also, if your application endpoints have long-running tasks, AWS Lambdas won’t be a recommended approach. Try to keep your task run times to well under 5 mins of execution time, as this can also contribute to the AWS Lambda costs. There is also a 1000 concurrent execution limit for the Lambda.

Thus, it’s pretty much clear that it’s not a very good idea to try to host complex applications into AWS Lambda. If you have a simple to medium Web API that maybe does some CRUD functionalities and connects to a few other simple AWS Services like DynamoDB, Cloudwatch, Kinesis, and S3, this approach will do wonders for you and incredibly optimize your AWS running costs.

Let’s get into the implementation and explore a couple of cool ways of hosting ASP.NET Core Web API with AWS Lambda! I assure you that you are going to learn a lot from this article. Leave a comment if you did.

Prerequisites

You will need the following for this implementation.

  • Visual Studio 2022 or other IDEs installed. I will be demonstrating this with VS 2022 Community Edition.
  • .NET6 SDK installed on your development machine.
  • AWS Account. A Free account is more than enough.
  • AWS CLI configured. You can follow the steps from here.
  • AWS Tools and toolkit installed. You can install this as an extension from the Visual Studio Extensions. Refer to steps from here.

Hosting ASP.NET Core Web API with AWS Lambda – Getting Started

First up, let’s build an ASP.NET Core Web API with Visual Studio using the default .NET templates, add in some changes to give it a Lambda Hosting, zip it up, and publish the Lambda using the AWS CLI. We will be doing this with and without the aws lambda configuration file. This approach is to help you understand what really happens behind the scene. Moving forward we will automate the step where you had to manually enter the lambda-related configuration and load it from a JSON file.

Creating the .NET 6 Web API Project

Let’s create a new .NET 6 Web API project and named it VerySimpleAPI. As the name suggests, this API will be just a plain default Web API. We will keep it simple to make the article compact. But you get the idea, it can be a full-fledged API as well (keeping in mind the pros and cons of this deployment strategy).

Keep in mind that this also can be an already existing .NET 6 Web API. We will just have to install a package to it and add a couple of lines of code to it to be able to deploy it into AWS Lambda.

devenv T7JPowRlsL Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

You can also choose the Minimal API approach if you want. But for this demo, I will showcase both the Controller and Minimal API endpoints within the same deployment.

devenv 3w29uH8tY6 Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

With that done, open up the Startup.cs and the following line just before the app.Run() line. This is just to add a minimal API endpoint to the application.

app.MapGet("/", () => "Hello from AWS Lambda!");

As of now, we just have 2 endpoints in the picture, which are the /weatherforecast (the one from the traditional API Controller) and / endpoint (from the newly created Minimal API route).

Installing the Required Lambda Package & Service Registration

Next, we need to install a package from AWS and add in a single line of service registration code which will automatically make the application use the Lambda Runtime. Open up the package manager console and run the following command to install the required package.

Install-Package Amazon.Lambda.AspNetCoreServer.Hosting

This is the only package you will need to turn your application into an AWS Lambda! As simple as that. With the package installed, let’s register the Lambda Hosting Service and mention the type of resource we intend to create. In our case, it will be an HTTP API. Add the following line of code in the Startup file right after the Controllers are registered in the application

builder.Services.AddAWSLambdaHosting(LambdaEventSource.HttpApi);

And would you be surprised if I told you that these are the only code changes actually required to make your ASP.NET Core Web API eligible to be deployed to AWS Infrastructure?  Now Lambda would recognize your entire API as a Function. This makes it so easy to get it deployed into AWS Lambda as well.

Deploying the AWS Lambda with CLI

Next, let’s open up the terminal right at the root of the project’s directory and use the AWS CLI and Toolkit to actually deploy the Lambda. Make sure to navigate to the folder where the csproj file exists.

Run the following command.

dotnet lambda deploy-function

Now, you will have to enter in some configuration to actually deploy the Lambda.

Firstly, the CLI asks you to enter the required runtime. In our case, it will be dotnet6, as this is the latest runtime available for .NET applications. Read more about Lambda Runtimes here.

WindowsTerminal sRzuppxuev Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

Once you enter the runtime, the cli publishes your ASP.NET Core Web API in release mode with Linux runtime and ZIPs it to {namespace}.zip which can be located inside the publish folder.

Nex,t follow the series of questions asked by the CLI

  • Enter the function name: simpleapi – This will be the internal name of the Lambda in AWS. This will create the Lambda for you.
  • Role Selection: Here you can select an already existing IAM role or create a new one. I created a new IAM role and named it simpleapirole.
  • Select Policy to attach with the IAM role. From the list that appears on the terminal, I selected #6 which points to a basic Lambda Execution Role. You can obviously select the policy based on your requirement, or even attach more policies to the role using the AWS Management Console. I did a similar thing in one of the previous articles, where my Lambda needed permission to access DynamoDB Table. Read about it here. This would create and propagate the IAM role into the AWS regions.
  • Enter memory size (MB): Here, let’s go with 256
  • Enter timeout (seconds): Proceed with 30
  • Enter Handler: Be careful here. This should be the name of the namespace of the API project. In our case it is VerySimpleAPI. When the Lambda is created it will be use the namespace as the entry point of the application. Make sure it’s set to the namespace / DLL name.
WindowsTerminal orG6mRGfcS Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

That’s it for the configurations! Your Lambda is now created. We have a couple of things to do before we test our deployment. Navigate to the AWS Management console’s AWS Lambda homepage.

If things went as expected, you will be able to see your Lambda Function.

chrome esOJhV5RUr Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

Lambda Function URLs

I earlier mentioned that in order to keep things simple we are not going to use the Amazon API Gateway to expose Lambda as a URL, right? So how are we going to do this? Well, there is this feature in AWS Lambdas known as function URLs wherein we can create access endpoints per Lambda without having to create an API Gateway at all.

Function URL is a dedicated HTTP endpoint for a Lambda function. When configured, the Function URL can be used to access the Lambda function via browser, client applications, and simple CURL requests. These URLs can be secured using AWS IAM Authorization. For now, we will be setting these endpoints as public.

Click on the Lambda Function Name. On the Lambda Dashboard, click on the Configuration Tab and select the Function URL.

image 5 Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

Here, click on Create Function URL and select the Auth type to None.

This means that AWS will not be responsible for securing access to your .NET 6 Web API. Rather, authentication and authorization will the responsibility of you as a developer and how you implement the Auth logic of your ASP.NET Core Web API. You can simply write in code that can handle Authentication using JWT tokens or OAuth, or anything you wish to.

Feel free to explore the CORS configuration as well. I kept it as it is. Click on save.

chrome 8Q3TGhkaPh Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

This would generate a Function URL that is linked with your Lambda.

chrome oNIEENiupx Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

Testing

Let’s use this Function URL and test it via our browser since we have not really added any POST / Delete / Patch methods to the endpoints. It’s just 2 simple GET endpoints if you remember. First, let’s test the / endpoint. And as we expected, we get a simple Hello message. Note that there is a slight delay in response, but just under a couple of seconds. When you retry the request, it’s much faster. This is because of the cold start of the AWS Lambda that we learned in the Pros and Cons section of this article.

Next, let’s navigate to the /weatherforecast endpoint. You can see that the response is pretty fast.

chrome 6efckF9G05 Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

Adding Environment Variables to the AWS Lambda

The swagger endpoint doesn’t seem to work though. This is because of our Startup file where we set the Swagger to be enabled only if the Environment is DEVELOPMENT. The simple fix here is to add a new environment variable to the AWS Lambda and set the ASPNETCORE ENVIRONMENT to Development.

Again, open up the Lambda Function and navigate to Configuration / Environment Variables and add a new one with the key as “ASPNETCORE_ENVIRONMENT” and value as “Development”.

chrome fJkBRV2ofR Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

Save it, give it a couple of seconds for the propagation to happen and then navigate to <function-url>/swagger

chrome miWaXeUa5H Hosting ASP.NET Core Web API with AWS Lambda - Truly Serverless REST APIs

There you go, Swagger is now accessible as well. I am actually enjoying working with .NET and AWS. The team has actually made it pretty intriguing to work with .NET applications.

That’s actually how simple it is for Hosting ASP.NET Core Web API with AWS Lambda! Now, there are certain parts of this approach that can be automated and made much easier to deploy. For example, in cases where you have made changes to the VerySimpleAPI project and want to re-deploy it to AWS Lambda, the CLI would again ask for the runtime, function name, handler, and roles and so much more. Remember entering these values in the CLI while creating the Lambda?

Or in case, where you need to deploy this API to another AWS account for some reason, you would have to manually go into the AWS Management Console to create a new function URL, and add a new environment variable.

Wouldn’t it make sense to store these values somewhere as configurations within the project so that the CLI can read the data from the configuration the next time we intend to deploy? That’s exactly what the AWS CLI does. All you have to do is just add in a new JSON file, fill in the required configuration one time, and from then on the CLI picks up the configuration and makes things much quicker for you! Let’s explore this now.

AWS Lambda CLI Functions

Before proceeding, let’s delete the Lambda that we deployed earlier. You can do this by navigating to the management console, selecting the Lambda function, and clicking on delete. But since we have AWS CLI already set up locally, I prefer to run a cli command that can delete the Lambda easily. To list the available Lambdas, run the following.aws lambda list-functions

To delete the Lambda, run the following.

aws lambda delete-function --function-name simpleapi

Now that our Lambda is removed, let’s continue.

Storing Lambda Configurations in aws-lambda-tools-defaults.json

Switch to Visual Studio. At the root of the project, add a new JSON file and name it aws-lambda-tools-defaults.json. This is the Default File Name expected by the AWS Lambda Tools CLI. There was no proper documentation for this file. So I dug up the Source from the AWS DOTNET CLI Repository. Here is the class for your reference. All the properties supported by the aws-lambda-tools-defaults.json file are listed in this class.

We would be adding some crucial configurations to this JSON file. Add the following content to your aws-lambda-tools-defaults.json file.

{ "profile": "", "region": "", "configuration": "Release", "function-runtime": "dotnet6", "function-memory-size": 256, "function-timeout": 30, "function-handler": "VerySimpleAPI", "function-name": "verysimpleapi", "environment-variables": "ASPNETCORE_ENVIRONMENT=Development;SOMETHING_ELSE=SomeValue", "function-url-enable": true}

As you see, since the profile and regions are already configured within the AWS CLI, we are keeping it empty. In case you need to deploy to another AWS region using a different configured local profile, you would have to modify these values.

Next up, the configuration is set to Release for optimizing the published package size, the runtime is set to dotnet6, memory size to 256, timeout to 30, handler to the namespace of the ASP.NET Core application, function name to verysimpleapi.

Then, remember we needed to add Environment variables to change the ASP.NET Core Environment to Development? So, to the environment-variables property, we add a list of key-value pairs using the following format -> “key1=value1;key2=value2”. I added a second dummy variable just to showcase the usage.

Finally, we set the function URL to enable the boolean to be true. This is to enable and create a Function URL that is associated with this Lambda. This also prints us the Function URL on the terminal once the Lambda is deployed, pretty handy, right? Thus the only property that we left out is the role and policy selection. This is to keep it flexible for adding new roles or using existing ones.

Let’s see our changes in action now. Save the changes and open up the terminal at the root of the project directory where the csproj file lives and run the deploy command again.dotnet lambda deploy-function

You can see that the Lambda gets deployed automatically using the values read from the configuration file. We will still have to enter the role to be used for this Lambda. Once that’s entered, the Lambda function is deployed and the Function URL is written onto the terminal window. Just click on the URL and you are all ready to test your new deployment. Attaching a screenshot for this.

Leave a Comment

Your email address will not be published. Required fields are marked *