Kanject.Core.CloudFunction.Aws.Annotations 1.8.2

Prefix Reserved
dotnet add package Kanject.Core.CloudFunction.Aws.Annotations --version 1.8.2
                    
NuGet\Install-Package Kanject.Core.CloudFunction.Aws.Annotations -Version 1.8.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Kanject.Core.CloudFunction.Aws.Annotations" Version="1.8.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kanject.Core.CloudFunction.Aws.Annotations" Version="1.8.2" />
                    
Directory.Packages.props
<PackageReference Include="Kanject.Core.CloudFunction.Aws.Annotations" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Kanject.Core.CloudFunction.Aws.Annotations --version 1.8.2
                    
#r "nuget: Kanject.Core.CloudFunction.Aws.Annotations, 1.8.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Kanject.Core.CloudFunction.Aws.Annotations@1.8.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Kanject.Core.CloudFunction.Aws.Annotations&version=1.8.2
                    
Install as a Cake Addin
#tool nuget:?package=Kanject.Core.CloudFunction.Aws.Annotations&version=1.8.2
                    
Install as a Cake Tool

Kanject.Core.CloudFunction.Aws.Annotations

A Roslyn source generator, with analyzers and code fixes, that removes the hand-written plumbing from AWS Lambda hosts built on Kanject.Core.CloudFunction.Provider.AwsLambda. You mark a partial class with [CloudFunctionHost] and write ConfigureServices. The generator emits everything else: the base class, the constructor, OnStartup, the assembly-level Lambda serializer, and bind-or-throw checks for required configuration sections.

Installation

<ItemGroup>
  <PackageReference Include="Kanject.Core.CloudFunction.Provider.AwsLambda" />                  
  <PackageReference Include="Kanject.Core.CloudFunction.Aws.Annotations" PrivateAssets="all" />
  <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" />                     
</ItemGroup>

If you don't use central package management, add Version="x.y.z" to each reference. From the command line:

dotnet add package Kanject.Core.CloudFunction.Aws.Annotations

Things to know about how this package is wired:

  • Reference it directly. Kanject.Core.CloudFunction.Provider.AwsLambda depends on this package. The provider's nuspec lists that dependency with exclude="Build,Analyzers", yet a project that references only the provider still gets the generator and its build targets (seen with .NET SDK 9.0.311 and 10.0.402). Don't rely on either behaviour. Reference the package yourself, so the generator version is explicit and doesn't depend on how NuGet resolves the provider's dependency.
  • Add PrivateAssets="all" yourself. The package is not marked as a development dependency, so dotnet add package writes a plain reference. PrivateAssets="all" stops the generator from flowing to projects that reference yours.
  • There is no separate .Attributes package. [CloudFunctionHost] and [RequireConfigSection<T>] live in Kanject.Core.CloudFunction.Abstractions, which comes with the provider.
  • The generated code needs the provider. It derives from the provider's CloudFunction. By default it also references Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer. With ConfigurationSource.AwsSystemManagerParameterStore, also reference Kanject.Core.Api.Aws.Extensions.
  • Frameworks and compiler. The package targets netstandard2.0 because it runs inside the compiler. Use it from projects that target .NET 8, .NET 9 or .NET 10 (the provider's frameworks). It is built against Roslyn 4.14 (Microsoft.CodeAnalysis.CSharp 4.14.0), so build with .NET SDK 9.0.300 or later, or Visual Studio 2022 17.14 or later. An older compiler would skip the generator (CS9057); the package's build targets stop the build with KANTC001 instead.
  • MSBuild defaults. The package's build targets set EnableConfigurationBindingGenerator to true for .NET 8+ projects unless you've already set it, so the generated Get<T>() calls bind without reflection. Set it to false in your project to opt out. Whenever the binder generator is on, whether by this default or by your own setting, the targets also add Microsoft.Extensions.Configuration.Binder.SourceGeneration to InterceptorsNamespaces. Without that, a .NET 9 SDK build of a project with a Microsoft.AspNetCore.App framework reference fails with CS9137.

Quick start

Before: a hand-written host.

using Amazon.Lambda.Core;
using Kanject.Core.Api.Aws.Extensions.Vault.ParameterStore;
using Kanject.Core.CloudFunction.Abstractions.Enums;
using Kanject.Core.CloudFunction.Provider.AwsLambda;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace Orders.Lambda;

public partial class Functions : CloudFunction
{
#if DEBUG
    public Functions() : base(CloudFunctionEnvironment.Development) { }
#else
    public Functions() : base() { }
#endif

    public override void OnStartup(IConfigurationBuilder configurationBuilder)
    {
#if DEBUG
        configurationBuilder.AddAwsSystemManagerParameterStore(fetchSecretPathFromAppSettings: true);
#else
        configurationBuilder.AddAwsSystemManagerParameterStore();
#endif
    }

    public override void ConfigureServices(IServiceCollection services)
    {
        var appSettings = Configuration.GetSection("AppSettings").Get<AppSettings>()
                          ?? throw new InvalidOperationException("'AppSettings' is required.");

        services.AddSingleton(appSettings);
        services.AddScoped<OrderService>();
    }

    public override void Configure(IServiceProvider serviceProvider) { }
}

After: the same host with the generator. AppSettings and OrderService are your own types.

using Kanject.Core.CloudFunction.Abstractions.Attributes;
using Kanject.Core.CloudFunction.Abstractions.Enums;
using Microsoft.Extensions.DependencyInjection;

namespace Orders.Lambda;

[CloudFunctionHost(
    DebugEnvironment = CloudFunctionEnvironment.Development,
    ConfigurationSource = ConfigurationSource.AwsSystemManagerParameterStore)]
[RequireConfigSection<AppSettings>("AppSettings")]
public partial class Functions
{
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton(AppSettings);   // generated property, already bound and validated
        services.AddScoped<OrderService>();
    }
}

Your Lambda handler methods stay where they were, in other partial files of the same class. The Kanject.Core.CloudFunction.Provider.AwsLambda package covers handlers, scopes and runtime behavior.

What gets generated

For each [CloudFunctionHost] class, the generator adds one file, {ClassName}.CloudFunctionHost.g.cs. The following is what it emits for the "after" example in a Debug build (license header, #nullable enable and doc comments omitted):

// <auto-generated/>
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Kanject.Core.CloudFunction.Abstractions.Enums;
using Kanject.Core.CloudFunction.Provider.AwsLambda;
using Kanject.Core.Api.Aws.Extensions.Vault.ParameterStore;

[assembly: global::Amazon.Lambda.Core.LambdaSerializerAttribute(typeof(global::Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace Orders.Lambda;

partial class Functions : global::Kanject.Core.CloudFunction.Provider.AwsLambda.CloudFunction
{
    public Functions() : base(global::Kanject.Core.CloudFunction.Abstractions.Enums.CloudFunctionEnvironment.Development) { }

    public global::Orders.Lambda.AppSettings AppSettings { get; private set; } = null!;

    public override void OnStartup(global::Microsoft.Extensions.Configuration.IConfigurationBuilder configurationBuilder)
    {
        configurationBuilder.AddAwsSystemManagerParameterStore(fetchSecretPathFromAppSettings: true);
        AddAdditionalConfigurationSources(configurationBuilder);
    }

    partial void AddAdditionalConfigurationSources(global::Microsoft.Extensions.Configuration.IConfigurationBuilder configurationBuilder);

    protected override void ConfigureLogging(global::Microsoft.Extensions.Logging.ILoggingBuilder logging)
    {
        AddAdditionalLoggingProviders(logging);
    }

    partial void AddAdditionalLoggingProviders(global::Microsoft.Extensions.Logging.ILoggingBuilder logging);

    protected override void RegisterFrameworkServices(global::Microsoft.Extensions.DependencyInjection.IServiceCollection services)
    {
        var validationConfiguration = base.Configuration;
        this.AppSettings = validationConfiguration.GetSection("AppSettings").Get<global::Orders.Lambda.AppSettings>()
            ?? throw new global::System.InvalidOperationException("Required configuration section 'AppSettings' is missing or could not bind to global::Orders.Lambda.AppSettings.");
    }
}

The generator reads the compilation's DEBUG symbol and writes only the matching branch, so the output contains no #if directives. A Release build of the same class emits public Functions() : base() { } and configurationBuilder.AddAwsSystemManagerParameterStore();. Deploy Release builds: a Debug build bakes DebugEnvironment into the constructor.

In Release, the Kanject.Core.Api.Aws.Extensions Parameter Store source reads the parameter path from the SECRET_PARAMETER_PATHNAME environment variable. In Debug with DebugFetchSecretPathFromAppSettings (the default), it reads AppSettings:SecretParameterPathName, AppSettings:AwsRegion and AppSettings:AwsProfile from the configuration built so far.

[CloudFunctionHost] options

Property Default Effect on the generated code
DebugEnvironment not set In Debug builds, the constructor passes this CloudFunctionEnvironment to the base. If you leave it unset, both configurations use base(), and the environment comes from ASPNETCORE_LAMBDA_ENVIRONMENT / ASPNETCORE_ENVIRONMENT.
ConfigurationSource None AwsSystemManagerParameterStore adds configurationBuilder.AddAwsSystemManagerParameterStore(...) to OnStartup.
DebugFetchSecretPathFromAppSettings true With Parameter Store, Debug builds call the fetchSecretPathFromAppSettings: true overload. Set it to false to emit the parameterless call in both configurations.
EmitLambdaSerializer true Emits [assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))]. Set it to false if the project declares its own serializer, which a project with Amazon.Lambda.Annotations [LambdaFunction] handlers must do (see below).
EnableAot false Derives from Kanject.Core.CloudFunction.Provider.AwsLambda.Aot.CloudFunction instead of the default host.
Provider AwsLambda The only supported value.

Required configuration sections

Each [RequireConfigSection<T>("Section")] adds two things:

  • A bind-or-throw check in a generated RegisterFrameworkServices override. The base host calls it after building its configuration from every source (the attribute-driven ones and your AddAdditionalConfigurationSources hook) and before ConfigureServices. The check reads that configuration, so no source, Parameter Store included, loads twice. If the section is missing, or doesn't bind to T, the cold start fails with InvalidOperationException and names the section.
  • A public property holding the bound instance. The property exists by the time ConfigureServices runs. The generator names it from PropertyName if you set it, otherwise from the section name if that is a valid C# identifier, otherwise from T's simple name. If an explicit PropertyName is not a valid identifier, the check still runs but no property is emitted.
[CloudFunctionHost]
[RequireConfigSection<AppSettings>("AppSettings")]                                  // property: AppSettings
[RequireConfigSection<QueueSettings>("Queues:Orders", PropertyName = "OrderQueue")] // property: OrderQueue
public partial class Functions { /* ... */ }

T can be a class or a struct. For a class (or a nullable struct such as int?) the property is initialised with null!, and validation throws when the section is missing or binds to null. A non-nullable struct can't be null, so its property starts at default and validation throws when the section doesn't exist. It does not register IOptions<T>; call services.Configure<T>(...) in ConfigureServices if you want options binding too. If two attributes resolve to the same property name, you get a duplicate-member compile error. Set PropertyName on one of them to fix it.

Extension points

The generator owns OnStartup and ConfigureLogging, and RegisterFrameworkServices when the class has a [RequireConfigSection<T>] or sets EnablePrintInConsoleLogging. It declares two optional partial-method hooks for you to implement. If you leave a hook unimplemented, the compiler removes its call.

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Orders.Lambda;

public partial class Functions
{
    // Runs at the end of the generated OnStartup, after the attribute-driven sources. The sources it
    // adds count for [RequireConfigSection] validation, which runs once the host has built them all.
    partial void AddAdditionalConfigurationSources(IConfigurationBuilder configurationBuilder)
    {
        configurationBuilder.AddJsonFile("features.json", optional: true);
    }

    // Runs after the base host's ClearProviders() + AddConsole().
    partial void AddAdditionalLoggingProviders(ILoggingBuilder logging)
    {
        logging.SetMinimumLevel(LogLevel.Information);
    }
}

Configure(IServiceProvider) remains yours to override for post-container work. If you need full control of OnStartup, remove the attribute and write the host by hand (KANCF003 enforces this).

Handlers with Amazon.Lambda.Annotations

If your handlers use Amazon.Lambda.Annotations' [LambdaFunction], set EmitLambdaSerializer = false and declare the serializer in your own source:

using Amazon.Lambda.Annotations;
using Kanject.Core.CloudFunction.Abstractions.Attributes;
using Kanject.Core.CloudFunction.Abstractions.Enums;
using Microsoft.Extensions.DependencyInjection;

[assembly: Amazon.Lambda.Core.LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]

namespace Orders.Lambda;

[CloudFunctionHost(DebugEnvironment = CloudFunctionEnvironment.Development, EmitLambdaSerializer = false)]
public partial class Functions
{
    public override void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<OrderService>();
    }

    [LambdaFunction]
    public async Task<OrderReceipt> PlaceOrder(PlaceOrderRequest request)
    {
        using var scope = ServiceScope;
        return await scope.ServiceProvider.GetRequiredService<OrderService>().PlaceAsync(request);
    }
}

Amazon's generator needs [LambdaSerializer] on each [LambdaFunction] method or on the assembly, and it reads only the source you wrote. Source generators can't see each other's output, so the attribute this generator emits never counts. Leave EmitLambdaSerializer on and the build fails with AWSLambda0108 ("Assembly attribute Amazon.Lambda.Core.LambdaSerializerAttribute is missing").

  • KANCF005 reports the same failure on the [CloudFunctionHost] attribute and says what to change. Its code fix, Declare the Lambda serializer by hand, sets EmitLambdaSerializer = false and writes the attribute above into the host's file. It names the same DefaultLambdaJsonSerializer the generator emits, so serialization doesn't change.
  • A method with its own serializer. A [LambdaFunction] method that carries [LambdaSerializer] itself doesn't need the assembly attribute.
  • Handlers on another class. KANCF005 also fires for [LambdaFunction] methods outside the host class, because the assembly attribute covers them too.
  • Construction. Without [LambdaStartup], Amazon's generated wrapper creates the class with its parameterless constructor, the one this generator emits, so the host starts as it does for a hand-written handler.
  • Native AOT. Declare a source-generated serializer instead (see Native AOT).

Migrating an existing host

The migration analyzer reports KANCF100 (Info) on a hand-written host that the generator can replace. The code fix, Migrate to [CloudFunctionHost], rewrites it. The analyzer only fires when all of these are true:

  • the class derives directly from Kanject.Core.CloudFunction.Provider.AwsLambda.CloudFunction, is partial, is not abstract, and doesn't already carry the attribute;
  • every declared constructor is parameterless and calls base() or base(CloudFunctionEnvironment.X);
  • OnStartup is empty or contains exactly one AddAwsSystemManagerParameterStore(...) call;
  • Configure(IServiceProvider) is absent or empty, and ConfigureServices is overridden;
  • the assembly declares [assembly: LambdaSerializer(typeof(DefaultLambdaJsonSerializer))].

The fix does the following:

  • Adds [CloudFunctionHost(...)], inferring DebugEnvironment from the constructor and ConfigurationSource from OnStartup.
  • Removes the constructors, OnStartup, the empty Configure and the : CloudFunction base.
  • Removes the LambdaSerializer assembly attribute when it is in the same file. If a [LambdaFunction] method relies on it, the fix keeps it and adds EmitLambdaSerializer = false instead.
  • Keeps ConfigureServices exactly as written.

Afterwards, check these by hand:

  • Run the fix in a Debug configuration so it can see a constructor behind #if DEBUG.
  • If your old Debug branch called AddAwsSystemManagerParameterStore() without arguments, add DebugFetchSecretPathFromAppSettings = false. The fix leaves that property at its default of true.
  • Remove a LambdaSerializer attribute that lives in another file (unless [LambdaFunction] methods need it), and any usings that are now unused.

Native AOT

EnableAot = true only selects the AOT-oriented host base class. The functions you register in ConfigureServices must be AOT-safe as well. DefaultLambdaJsonSerializer uses reflection-based System.Text.Json, so for an AOT function set EmitLambdaSerializer = false and declare your own source-generated serializer, such as SourceGeneratorLambdaJsonSerializer<TContext> from Amazon.Lambda.Serialization.SystemTextJson.

Diagnostics

ID Severity What it means
KANCF001 Error The [CloudFunctionHost] class is not partial (code fix: Make class partial).
KANCF003 Error The class declares its own OnStartup override, which the generator owns. Use AddAdditionalConfigurationSources, change ConfigurationSource, or drop the attribute.
KANCF004 Error More than one [CloudFunctionHost] class exists in the assembly (the Lambda serializer attribute is assembly-wide).
KANCF005 Error The host leaves EmitLambdaSerializer on, but a [LambdaFunction] method needs a serializer Amazon.Lambda.Annotations can see (it reports AWSLambda0108). Code fix: Declare the Lambda serializer by hand.
KANCF100 Info A hand-written host matches the migration shape (code fix: Migrate to [CloudFunctionHost]).

There is no KANCF002. If the class declares a base type other than CloudFunction, the compiler rejects it, because the generated partial fixes the base class.

Package Role Availability
Kanject.Core.CloudFunction.Provider.AwsLambda The Lambda host runtime whose CloudFunction base the generated code extends nuget.org
Kanject.Core.CloudFunction.Abstractions Defines [CloudFunctionHost], [RequireConfigSection<T>] and the option enums (arrives with the provider) nuget.org
Kanject.Core.Api.Aws.Extensions Supplies AddAwsSystemManagerParameterStore for ConfigurationSource.AwsSystemManagerParameterStore nuget.org
Kanject.Core.Queue.Provider.AwsSqs SQS queue consumers that you can dispatch from the host's Lambda handlers nuget.org

License

Licensed under the Kanject Code Libraries License Agreement (KCLLA); the full text ships in this package as LICENSE.md. Organizations whose trailing-twelve-month gross revenue and total funding raised are each below US$250,000 may use it at no cost under the Free Tier. At or above either threshold a commercial license is required — contact commercial@kanjectbusiness.com.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Kanject.Core.CloudFunction.Aws.Annotations:

Package Downloads
Kanject.Core.CloudFunction.Provider.AwsLambda

Kanject core cloud function aws lambda provider

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.8.2 6 11/2/2026
1.8.1 245 10/14/2026
1.8.0 217 10/5/2026
1.7.0 119 10/2/2026
1.6.1 141 9/27/2026
1.6.0 114 9/27/2026
1.5.7 130 9/26/2026
1.5.6 160 9/7/2026
1.5.5 139 8/27/2026
1.5.4 151 8/22/2026
1.5.3 152 8/10/2026
1.5.2 143 8/9/2026
1.5.1 139 8/5/2026
1.5.0 141 8/5/2026
1.4.0 156 8/3/2026
1.3.5 160 7/30/2026
1.3.4 162 7/18/2026
1.3.3 159 7/13/2026
1.3.2 156 7/11/2026
1.3.1 154 7/11/2026
Loading failed

- KANCF005 explains AWSLambda0108 beside [LambdaFunction] methods and its code fix declares the Lambda serializer by hand. The KANCF100 migration no longer deletes that serializer.
- [RequireConfigSection] binds from the configuration the host already built so Parameter Store loads once per cold start instead of twice.
- Single-targeted .NET 8+ projects get the configuration binding generator by default and .NET 9 SDK builds no longer fail with CS9137.