Running serverless .NET applications in AWS Lambda

Amazon simplifies writing Lambda functions in C# with features like Lambda Annotations, which uses C# source generators to generate code from a REST API path. Support for .NET 8 is coming soon.

Lambda expressions  >  Lambda symbol / circuits / puzzle pieces
GreyFebruary / Getty Images

The recent evolution of .NET has been fun to watch. Since .NET became an open-source platform, it has finally delivered on its cross-platform promise. At the same time, support for Linux has given it more traction in the cloud-native space, with the latest releases supporting container runtimes.

Having cross-platform capabilities means that you can run .NET in any cloud, too. All you need is a supported Linux virtual machine host or a Kubernetes instance that supports distro-less containers. That’s enough to run .NET code on infrastructure as a service platforms, like AWS, or on managed Kubernetes like Google Kubernetes Engine (GKE). Code can migrate from platform to platform, using REST APIs to access platform services. In some cases, there are SDKs, either from the platform provider or developed by the community.

Portability like this is a good thing: It allows you to move from cloud to cloud, with minimal changes to your code (especially if you’re not using any service-specific applications). But there are limitations, as you can’t take advantage of serverless platform features that allow you leverage the scalability of the cloud, and the economic benefits that come with on-demand operations. Without them you’re simply lifting and shifting on-premises .NET code.

Using C# in AWS Lambda

If you’re using AWS Lambda for your serverless applications, you’ve had the option of using .NET with C# for some time now, alongside JavaScript, Go, Python, Java, Ruby, Rust, PowerShell, and TypeScript. Amazon support began with .NET Core, and has been updated with successive releases of the platform. Currently there’s support for both .NET 6 and .NET 7. You will most likely want to use .NET 6 for now, as .NET 7 is only available for hosted containers.

Much like Azure Functions, AWS Lambda is a serverless compute platform built around event-driven operations. Lambda functions are triggered by events, often from other AWS services, and can be used for data processing, stream processing, API-driven back ends for web and mobile applications, and to support IoT (internet of things) deployments, among many different options.

The most important aspect of AWS Lambda is that, like Azure Functions, you have no control over the compute resources it uses. The service scales on demand, and you pay for the resources you consume.

Building Lambda functions in .NET

Using .NET with AWS Lambda requires no changes to your development toolbox. You can use Visual Studio, Visual Studio Code, or any third-party IDE. All you need do is install a set of AWS templates from NuGet via the .NET CLI.

At the heart of AWS’s C# functions is a Lambda function handler. This method is what the underlying service invokes to launch your code. It’s an essential component of a Lambda function, delivering both an event and a context object to your code. The event object is probably the most useful, as it delivers information about the event, while the context object delivers information about the runtime environment. Data will need to be serialized as a JSON object ready for use in your code.

Understanding the context object is important to ensuring your C# code will run well. The important runtime information it provides includes the amount of time available before a function times out and AWS takes back its resources. You can use this information to write appropriate error handling controls, cancelling tasks and delivering notifications if a timeout is about to be triggered.

C# code in AWS Lambda is called in one of two ways. The first option is to provide a function as a class library, configuring the service with its class and assembly names, and the method that will be called when the function is triggered. The second option is to provide an executable assembly that will be run when invoked.

Simplifying C# function development with Lambda Annotations

Amazon provides additional features that can simplify writing a C# function. The Lambda Annotations framework is a way of hiding much of the Lambda-specific code from your business logic, using source generators to create it from a REST API path, at the same time constructing the appropriate Lambda handlers. You can find a template for building an Annotations Framework project in the AWS Toolkit for Visual Studio, as part of the bundled blueprints.

Because the Annotations Framework can programmatically set Lambda properties, you’re able to add timeouts and memory limits as part of the initial function definition. Once your code is ready, simply build it and deploy it directly to AWS from inside Visual Studio.

One option with .NET 7-based functions is to use AOT (ahead-of-time) compilation to reduce startup times. As AOT needs to run in the target environment, you’re compiling code in an Amazon Linux container, using Docker as a host. It’s a relatively simple process, whereby you use the .NET CLI and the Lambda templating to download the Linux image. The compilation is run automatically as part of deploying your code to AWS.

You’re not limited to standalone C# applications. Lambda can be used to host and run ASP.NET Core web applications too, giving you an on-demand back end for sites that see relatively low usage or that need to respond to bursty demands.

Using .NET 8 in AWS Lambda

Amazon is working to deliver .NET 8 support for AWS Lambda hosts, with the final release is due soon. As the GitHub issue notes, there are a lot of moving parts that must come together to deliver a long-term stable release of a managed runtime. In addition to building a new host based on the latest releases of Amazon’s own internal Linux distribution, AWS’s .NET team is also developing and testing an updated set of .NET APIs and CLI tools to help build new Lambdas and update existing code.

That last point is important, as AWS plans to start deprecating both its .NET 6 and .NET 7 support in 2024, with a hard limit for updating .NET 6 functions in February 2025. Migrating to the long-term support release of .NET will help ensure your code remains supported—by both Microsoft and Amazon. Some tools are already available, including an update to the AWS Toolkit for Visual Studio, which lets you build custom runtime templates based on .NET 8, and support for a .NET 8 container base image.

If you plan on using this Amazon Linux 3 base image, you’ll need to clone the AWS .NET GitHub repository and build the image on your own development systems (see this blog post). This will allow you to test code before packaging and deploying it to AWS. When AWS finalizes its .NET 8 tools, this will become part of the platform, and you will be able to use it as part of your standard build process.

Support for .NET in AWS AWS Lamba makes your .NET skills portable beyond traditional application development and Azure cloud-native platforms. It’s important to note that this is not a one-off, but a long-term project that has been through multiple updates to the underlying runtime, in line with .NET’s own support life cycle. With an effective set of abstractions that make it easier to concentrate on your code, AWS is delivering an approach that should simplify porting serverless .NET code from other cloud platforms as well as from on-premises applications.

Copyright © 2024 IDG Communications, Inc.