Skip to content

Conversation

@normj
Copy link
Member

@normj normj commented Dec 5, 2025

Important Note: Lambda .NET 10 support is not released yet. This PR is in preparation for the support.

Description of changes:
A new feature of .NET 10 is the ability to have a file-based C# application. This creates the opportunity to create single file based .NET Lambda functions like the following

#:package Amazon.Lambda.Core@2.8.0
#:package Amazon.Lambda.RuntimeSupport@1.14.1
#:package Amazon.Lambda.Serialization.SystemTextJson@2.4.4

using Amazon.Lambda.Core;
using Amazon.Lambda.RuntimeSupport;
using Amazon.Lambda.Serialization.SystemTextJson;
using System.Text.Json.Serialization;

// The function handler that will be called for each Lambda event
var handler = (string input, ILambdaContext context) =>
{
    return input.ToUpper();
};

// Build the Lambda runtime client passing in the handler to call for each
// event and the JSON serializer to use for translating Lambda JSON documents
// to .NET types.
await LambdaBootstrapBuilder.Create(handler, new SourceGeneratorLambdaJsonSerializer<LambdaSerializerContext>())
        .Build()
        .RunAsync();


[JsonSerializable(typeof(string))]
public partial class LambdaSerializerContext : JsonSerializerContext
{
}

To make it easier for developers to write file-based C# Lambda functions Amazon.Lambda.Tools is being updated to not always assume there is a project file and instead handle the target being a C# file. For the deploy-function and package command the C# file can be pass as additional argument like:

dotnet lambda deploy-function ToUpper ToUpper.cs --function-runtime dotnet10 --function-role <role-arn> --function-memory-size 512 --function-timeout 30

In the CloudFormation commands deploy-serverless and package-ci the C# file is references as the CodeUri in the CloudFormation template. Since the file-based Lambda function will be packages as a .NET executable the Handler field
must be set to the .NET assembly. In the case of file-based C# applications the assembly will be the filename minus the extension.

"ToUpperFunction" : {
    "Type" : "AWS::Serverless::Function",
    "Properties": {
    "Handler": "ToUpperFunction",
    "Runtime": "dotnet10",
    "CodeUri": "./ToUpperFunction.cs",
    "MemorySize": 256,
    "Timeout": 30,
...
    }
}

Native AOT

By default when file based C# applications are published Native AOT is enabled. Amazon.Lambda.Tools will use a container build by default for Native AOT unless running on Amazon Linux. That requires Docker to be running to package file-based C# Lambda functions. Native AOT can be disabled for file-based C# applications by adding the #:property PublishAot=false to the top of the file along with the other compiler directives.

Debugging

VS Code with the C# Dev Kit supports debugging C# file-based applications. To debug a C# Lambda function first install the .NET Lambda Test Tool using the command dotnet tool install -g Amazon.Lambda.TestTool then in a separate terminal start the test tool to run the Lambda API emulator. dotnet lambda-test-tool start --lambda-emulator-port 5050.

By default the C# Dev Kit dynamically creates a launch configuration which doesn't provide an opportunity to set environment variables. Below are the config files I used configure the launch configuration manually with a preLaunchTask config to build the C# file into a DLL. It works for whatever is the current active file.

.vscode/launch.json

{
  "version": "0.2.0",
  "configurations": [

    {
      "name": "LambdaDebugFile",
      "type": "coreclr",
      "request": "launch",
      "program": "${fileDirname}/artifacts/Debug/${fileBasenameNoExtension}.dll",
      "cwd": "${workspaceFolder}",
      "console": "internalConsole",
      "stopAtEntry": false,
      "env": {
        "AWS_LAMBDA_RUNTIME_API": "localhost:5050/${fileBasenameNoExtension}"
      },
      "preLaunchTask": "build-active-file"
    }
  ]
}

.vscode/task.json

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build-active-file",
      "command": "dotnet",
      "type": "process",
      "args": [
        "build",
        "${file}",
        "--output", 
        "./artifacts/Debug"
      ],
      "problemMatcher": "$msCompile"
    }
  ]
}

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@normj normj marked this pull request as draft December 5, 2025 01:32
@normj normj marked this pull request as ready for review December 5, 2025 18:00
runtime-versions:
dotnet: 8.x
build:
commands:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since CodeBuild doesn't natively support .NET 10 yet I had to update the buildspec to install .NET 10 from MSFT to run the new unit tests that require .NET 10.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for deploying file-based C# Lambda functions in preparation for .NET 10, which introduces the ability to write single-file C# applications. This feature allows developers to create Lambda functions from a single .cs file instead of requiring a full project structure.

Key changes include:

  • Support for passing .cs files as arguments to deploy-function and package commands
  • Automatic detection and handling of file-based Lambda functions vs traditional project-based functions
  • Target framework determination from in-file compiler directives or Lambda runtime
  • Native AOT enabled by default for file-based functions (can be disabled with #:property PublishAot=false)

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 26 comments.

Show a summary per file
File Description
testapps/SingeFileLambdaFunctions/serverless.template CloudFormation template for testing single-file Lambda functions
testapps/SingeFileLambdaFunctions/ToUpperFunctionNoAOT.cs Test single-file Lambda function with AOT disabled
testapps/SingeFileLambdaFunctions/ToUpperFunctionImplicitAOT.cs Test single-file Lambda function with implicit AOT enabled
test/Amazon.Lambda.Tools.Test/LambdaSingleFilePackageTests.cs Comprehensive unit tests for single-file packaging, path handling, and framework detection
test/Amazon.Lambda.Tools.Test/UtilitiesTests.cs Added test cases for .NET 10 build images
test/Amazon.Lambda.Tools.Integ.Tests/DeployServerlessTests.cs Integration test for deploying serverless templates referencing single files
test/Amazon.Lambda.Tools.Integ.Tests/DeployProjectTests.cs Integration test for deploying single C# file directly as Lambda function
src/Amazon.Lambda.Tools/TemplateProcessor/TemplateProcessorManager.cs Updates to handle single C# files in CloudFormation templates
src/Amazon.Lambda.Tools/Program.cs Updated command arguments constant reference
src/Amazon.Lambda.Tools/LambdaUtilities.cs Added .NET 10 support, target framework detection for single files, and updated build image logic
src/Amazon.Lambda.Tools/LambdaPackager.cs Modified packaging logic to handle single files and skip legacy checks for them
src/Amazon.Lambda.Tools/LambdaDefinedCommandOptions.cs Updated handler option description to cover both class library and executable formats
src/Amazon.Lambda.Tools/Commands/PackageCommand.cs Added support for accepting single C# files as arguments
src/Amazon.Lambda.Tools/Commands/DeployFunctionCommand.cs Enhanced to handle single file deployment and automatic handler detection
src/Amazon.Common.DotNetCli.Tools/Utilities.cs Added IsSingleFileCSharpFile() method and updated path handling for single files
src/Amazon.Common.DotNetCli.Tools/Commands/BaseCommand.cs Handle working directory when set to a file instead of directory
buildtools/ci.buildspec.yml Added .NET 10 SDK installation for CI builds
aws-extensions-for-dotnet-cli.sln Added single-file Lambda test functions to solution
.gitignore Added artifacts folder to ignore list
.autover/changes/b30ca600-2c50-4ed1-91d0-610f711b9d88.json Version change metadata for the new feature

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

@GarrettBeatty GarrettBeatty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good. can you add the one comment and then also fix the typo in the test project/code

@normj normj force-pushed the normj/file-based branch 10 times, most recently from d29ff73 to e8222b7 Compare December 6, 2025 01:43
@normj normj force-pushed the normj/file-based branch 3 times, most recently from 5fcd04f to f829574 Compare December 6, 2025 01:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants