AWS Lambda provides developers with the feature to run their code without having to set up and maintain a server. The advantage is that they can concentrate on developing, rather than worrying about administration details. AWS Lambda functions are triggered by events in S3 buckets or from Amazon API Gateway HTTP request. In this article we will discuss how you would deploy .Net Core APIs as a service using AWS Lambda and call it from an Angular application as an endpoint.
Create AWS Lambda function using Visual Studio
There are many ways to create AWS Lambda function, you can use even notepad and create it but you may need some manual configuration. Visual studio provides different AWS templates to create AWS Lambda function, select the template as shown below. Here I am using C#
In this example, I am using .Net Core 3.1. If you want to create it using .Net Core 5.0 then you have to select Custom Runtime Function since AWS doesn’t have .Net 5.0 runtime configured in AWS Lambda function.
Select Empty function and click on Finish button. Visual Studio will create the solution and project for you. Now you can start adding the .Net Core APIs to it. Visual Studio will show the screen as shown below:
You have to configure your AWS account to deploy it to AWS, but you will be able to run it without configuring the AWS on your local machine. Project has an extra json file called aws-lambda-tools-defaults.json which will have the lambda function configuration.
{
"Information": [
"This file provides default values for the deployment wizard inside Visual Studio and the AWS Lambda commands added to the .NET Core CLI.",
"To learn more about the Lambda commands with the .NET Core CLI execute the following command at the command line in the project root directory.",
"dotnet lambda help",
"All the command line options for the Lambda command can be specified in this file."
],
"profile": "default",
"region": "us-west-2",
"configuration": "Release",
"framework": "netcoreapp3.1",
"function-runtime": "dotnetcore3.1",
"function-memory-size": 256,
"function-timeout": 30,
"function-handler": "TestAWS::TestAWS.Function::FunctionHandler"
}
You can configure the Lambda function memory, AWS region in this file as shown above. I would like to focus specifically on two parameters which I highlighted above. “Function-runtime” parameter sets the required Lambda function runtime and this should be one of the available runtime in AWS Lambda environment. If you want to use .Net 5.0, you have to configure the function-runtime as “customruntime”.
Here we will be making changes to use ASP.Net Core API Services. First you need to add the Nuget package Amazon.Lambda.ASPNetCore to use the ASP.Net Core services. Choose the appropriate version which supports on your local machine. You may have version issues with Amazon.Lambda.Serialization.SystemTextJson and you may need to choose older version to resolve this issue.
Now you need to make the changes in Function.cs file as shown below to enable ASP.Net Core API services.
using Amazon.Lambda.Core;
using Microsoft.AspNetCore.Hosting;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace TestAWS
{
public class Function : Amazon.Lambda.AspNetCoreServer.APIGatewayProxyFunction
{
/// <summary>
///
/// </summary>
/// <param name="builder"></param>
protected override void Init(IWebHostBuilder builder)
{
builder
.UseStartup<Startup>();
}
}
}
Here we are using the ASP.Net Core API startup file in the same way how we are doing for Asp.Net core API application. Inherit APIGatewayProxyFunction and implement the Init method. APIGatewayProxyFunction is the base class for Lambda functions hosting the ASP.NET Core framework and exposed to the web via API Gateway.
You need to update the aws-lambda-tools-defaults.json file to point to the correct Lambda function since you have removed the method from this class. “Function-handler” should point to FunctionHAndlerAsync method which is available in AbstractAspNetCoreFunction class. AbstractAspNetCoreFunction is the base class of APIGatewayProxyFunction class.
"function-handler": "TestAWS::TestAWS.Function::FunctionHandlerAsync"
We need to add the startup.cs file since we have made that as startup file in the Init, you can give any name but I have used standard name here.
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
namespace TestAWS
{
public sealed class Startup
{
public Startup()
{
}
/// <summary>
/// This method gets called by the runtime. Use this method to add services to the container.
/// </summary>
/// <param name="services">ServiceCollection object.</param>
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc();
}
/// <summary>
/// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
/// </summary>
/// <param name="applicationBuilder">ASP.Net Application Builder object.</param>
public void Configure(IApplicationBuilder applicationBuilder)
{
try
{
applicationBuilder
.UseHsts()
.UseRouting()
.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
catch (Exception exception)
{
throw exception;
}
}
}
}
Now you have added the Lambda function and also the .Net API code. Now we need to add the controllers in the code. I am creating test controller called CustomerController under controllers folder.
using Microsoft.AspNetCore.Mvc;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace TestAWS.Controllers
{
[Route("customers")]
public sealed class CustomerController: Controller
{
public CustomerController()
{ }
[HttpGet]
public async Task<IActionResult> GetAll()
{
return Ok(
await GetCustomers());
}
private async Task<IList<Customer>> GetCustomers()
{
IList<Customer> customers = new List<Customer>();
customers.Add(new Customer { Id = 1, CustomerName = "Customer1" });
//This should be DB Call and you should not use Task.FromResult
return await Task.FromResult(customers);
}
}
}
Customer.cs
namespace TestAWS.Controllers
{
public sealed class Customer
{
public int Id { get; set; }
public string CustomerName { get; set; }
}
}
Now you are ready to run your application using Lambda Test tool. You may refer the following link on installing the Lambda test tool:
https://www.nuget.org/packages/Amazon.Lambda.TestTool-3.1/
Make sure that you are configuring the Lambda Test tool in launchSettings.json file as shown below:
{
"profiles": {
"Mock Lambda Test Tool": {
"commandName": "Executable",
"executablePath": "C:\\Users\\%USERNAME%\\.dotnet\\tools\\dotnet-lambda-test-tool-3.1.exe",
"commandLineArgs": "--port 5050",
"workingDirectory": ".\\bin\\$(Configuration)\\netcoreapp3.1"
}
}
}
Modify the executable path if you OS drive is different.
You will be getting the following screen and pass the .net core API details in Function input.
{
"httpMethod":"get",
"path":"/customers"
}
Here I need to call HttpGet method of customer controller. This is only to test everything is working fine.
You can add a Program.cs and run it using dotnet command or add swagger and run it using swagger. You may need to Swashbuckly library for create the Swagger json file.
Program.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace TestAWS
{
public sealed class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
host.Run();
}
/// <summary>
/// Creating the Host builder for ASP.Net Core API.
/// </summary>
/// <param name="args">Parameters to the builder.</param>
/// <returns>Returns the HostBuilder object with startup file.</returns>
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}
}
Next step is to publish the Lambda function AWS using publish AWS Lambda option.
Build the Rest API from API Gateway (Click on create button and select Rest API from the wizard). Create the new resource as shown below. Resource name should be same as the API name.
You can test the API using Test option and you will be able to see the results. You have to deploy the API to access it from outside world using the deploy option.
You will be able to create swaggor.json file using Swashbuckle library. You can find the details in the following link:
And use terraform to create endpoints in API Gateway in AWS. It will be easy to deploy it automatically.
Manoharan Kanakathidathil
Architect, iDEAS - App Engineering & Modernization
Manoharan has around 19 years experience in Microsoft technologies and also relevant experience in Azure and AWS. He is working as an Architect in Microsoft practice currently.