From f2d637c7da15b3ecef25b784d7a90bc54e9d4b79 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Mon, 15 Dec 2025 20:54:21 -0500 Subject: [PATCH 01/27] feat(minimal-lambda): add `LifetimeStopwatch` to track application lifetime - Introduced `LifetimeStopwatch` class to monitor elapsed time since application start. - Registered `LifetimeStopwatch` as a singleton in `LambdaApplicationBuilder`. --- .../Builder/LambdaApplicationBuilder.cs | 3 +++ .../Core/Context/LifetimeStopwatch.cs | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/MinimalLambda/Core/Context/LifetimeStopwatch.cs diff --git a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs index f8405bfd..07587991 100644 --- a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs @@ -46,6 +46,8 @@ public sealed class LambdaApplicationBuilder : IHostApplicationBuilder /// Main internal constructor. internal LambdaApplicationBuilder(LambdaApplicationOptions? settings) { + var lifetimeStopwatch = new LifetimeStopwatch(); + settings ??= new LambdaApplicationOptions(); if (!settings.DisableDefaults) @@ -97,6 +99,7 @@ internal LambdaApplicationBuilder(LambdaApplicationOptions? settings) // Register core services that are required for Lambda Host to run Services.AddLambdaHostCoreServices(); + Services.AddSingleton(lifetimeStopwatch); } /// diff --git a/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs b/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs new file mode 100644 index 00000000..4f19d4fb --- /dev/null +++ b/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs @@ -0,0 +1,17 @@ +using System.Diagnostics; + +namespace MinimalLambda; + +internal sealed class LifetimeStopwatch +{ + private readonly Stopwatch _stopwatch = new(); + + internal TimeSpan Elapsed + { + get + { + Thread.MemoryBarrier(); + return _stopwatch.Elapsed; + } + } +} From fb0f48f1c2c4da19b9d214f8c1692294c7a85efc Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Mon, 15 Dec 2025 21:30:22 -0500 Subject: [PATCH 02/27] feat(minimal-lambda): add `ILambdaLifecycleContext` interface for Lambda lifecycle management - Introduced `ILambdaLifecycleContext` to encapsulate Lambda lifecycle event information such as initialization and shutdown. - Added properties like `CancellationToken`, `ElapsedTime`, `FunctionName`, `Region`, and other environment-specific details. - Intended to provide shared context for Lambda handlers. --- .../Core/ILambdaLifecycleContext.cs | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/MinimalLambda.Abstractions/Core/ILambdaLifecycleContext.cs diff --git a/src/MinimalLambda.Abstractions/Core/ILambdaLifecycleContext.cs b/src/MinimalLambda.Abstractions/Core/ILambdaLifecycleContext.cs new file mode 100644 index 00000000..eb935f5d --- /dev/null +++ b/src/MinimalLambda.Abstractions/Core/ILambdaLifecycleContext.cs @@ -0,0 +1,106 @@ +namespace MinimalLambda; + +/// +/// Encapsulates the information available during Lambda lifecycle events such as +/// initialization and shutdown. +/// +public interface ILambdaLifecycleContext +{ + /// + /// Gets the that signals the Lambda lifecycle event is being + /// canceled. + /// + /// + /// The cancellation token will also be cancelled if a SIGTERM signal is received, indicting + /// that the Lambda runtime is being terminated. + /// + CancellationToken CancellationToken { get; } + + /// Gets or sets a key/value collection that can be used to share data between handlers. + IDictionary Properties { get; } + + /// + /// Gets or sets the that provides access to the invocation's + /// service container. + /// + IServiceProvider ServiceProvider { get; } + + /// Gets the elapsed time since the Lambda execution environment was started. + TimeSpan ElapsedTime { get; } + + /// Gets the AWS region where the Lambda function is running, or null if not set. + /// + /// This value is read from the AWS_REGION environment variable. If both + /// AWS_REGION and AWS_DEFAULT_REGION are set, AWS_REGION takes precedence. + /// + string? Region { get; } + + /// Gets the runtime identifier, or null if not set. + /// + /// This value is read from the AWS_EXECUTION_ENV environment variable, which is + /// prefixed by AWS_Lambda_ (for example, AWS_Lambda_dotnet8). This environment + /// variable is not defined for OS-only runtimes. + /// + string? ExecutionEnvironment { get; } + + /// Gets the name of the Lambda function, or null if not set. + /// + /// This value is read from the AWS_LAMBDA_FUNCTION_NAME environment variable set by + /// AWS Lambda at cold start. + /// + string? FunctionName { get; } + + /// + /// Gets the amount of memory available to the function in MB, or null if not set or + /// cannot be parsed. + /// + /// + /// This value is read from the AWS_LAMBDA_FUNCTION_MEMORY_SIZE environment variable + /// set by AWS Lambda at cold start. + /// + int? FunctionMemorySize { get; } + + /// Gets the version of the function being executed, or null if not set. + /// + /// This value is read from the AWS_LAMBDA_FUNCTION_VERSION environment variable set by + /// AWS Lambda at cold start. + /// + string? FunctionVersion { get; } + + /// Gets the initialization type of the function, or null if not set. + /// + /// This value is read from the AWS_LAMBDA_INITIALIZATION_TYPE environment variable. + /// Possible values include: on-demand, provisioned-concurrency, snap-start, + /// or lambda-managed-instances. + /// + string? InitializationType { get; } + + /// + /// Gets the name of the Amazon CloudWatch Logs group for the function, or null if not + /// set. + /// + /// + /// This value is read from the AWS_LAMBDA_LOG_GROUP_NAME environment variable set by + /// AWS Lambda at cold start. This environment variable is not available in Lambda SnapStart + /// functions. + /// + string? LogGroupName { get; } + + /// + /// Gets the name of the Amazon CloudWatch Logs stream for the function, or null if not + /// set. + /// + /// + /// This value is read from the AWS_LAMBDA_LOG_STREAM_NAME environment variable set by + /// AWS Lambda at cold start. This environment variable is not available in Lambda SnapStart + /// functions. + /// + string? LogStreamName { get; } + + /// Gets the path to the Lambda function code, or null if not set. + /// + /// This value is read from the LAMBDA_TASK_ROOT environment variable set by AWS Lambda + /// at cold start. + /// + string? TaskRoot { get; } +} From 5fda15ed1926a799dc5f8bea00c962e654fb6d54 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 09:11:19 -0500 Subject: [PATCH 03/27] feat(minimal-lambda): implement factory and context for Lambda lifecycle - Added `LambdaLifecycleContext` class implementing `ILambdaLifecycleContext` for shared lifecycle context. - Introduced `LambdaLifecycleContextFactory` for creating `LambdaLifecycleContext` instances. - Updated `LambdaLifecycleContext` to include core Lambda environment details and integrate with DI. - Includes disposal logic to properly manage resources like `IServiceScope`. --- .../Context/ILambdaLifecycleContextFactory.cs | 9 +++ .../Core/Context/LambdaLifecycleContext.cs | 67 +++++++++++++++++++ .../Context/LambdaLifecycleContextFactory.cs | 45 +++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 src/MinimalLambda/Core/Context/ILambdaLifecycleContextFactory.cs create mode 100644 src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs create mode 100644 src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs diff --git a/src/MinimalLambda/Core/Context/ILambdaLifecycleContextFactory.cs b/src/MinimalLambda/Core/Context/ILambdaLifecycleContextFactory.cs new file mode 100644 index 00000000..5e1de4dd --- /dev/null +++ b/src/MinimalLambda/Core/Context/ILambdaLifecycleContextFactory.cs @@ -0,0 +1,9 @@ +namespace MinimalLambda; + +internal interface ILambdaLifecycleContextFactory +{ + ILambdaLifecycleContext Create( + IDictionary properties, + CancellationToken cancellationToken + ); +} diff --git a/src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs b/src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs new file mode 100644 index 00000000..b341db7d --- /dev/null +++ b/src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs @@ -0,0 +1,67 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace MinimalLambda; + +internal class LambdaLifecycleContext( + LambdaLifecycleContext.Core contextCore, + IServiceScopeFactory scopeFactory, + IDictionary properties, + CancellationToken cancellationToken +) : ILambdaLifecycleContext, IAsyncDisposable +{ + private IServiceScope? _instanceServicesScope; + + public CancellationToken CancellationToken { get; } = cancellationToken; + + public IServiceProvider ServiceProvider + { + get + { + if (field is null) + { + _instanceServicesScope = scopeFactory.CreateScope(); + field = _instanceServicesScope.ServiceProvider; + } + + return field; + } + private set; + } + + public IDictionary Properties { get; } = properties; + + public TimeSpan ElapsedTime => contextCore.Stopwatch.Elapsed; + public string? Region => contextCore.Region; + public string? ExecutionEnvironment => contextCore.ExecutionEnvironment; + public string? FunctionName => contextCore.FunctionName; + public int? FunctionMemorySize => contextCore.FunctionMemorySize; + public string? FunctionVersion => contextCore.FunctionVersion; + public string? InitializationType => contextCore.InitializationType; + public string? LogGroupName => contextCore.LogGroupName; + public string? LogStreamName => contextCore.LogStreamName; + public string? TaskRoot => contextCore.TaskRoot; + + public async ValueTask DisposeAsync() + { + if (_instanceServicesScope is IAsyncDisposable instanceServicesScopeAsyncDisposable) + await instanceServicesScopeAsyncDisposable.DisposeAsync(); + + _instanceServicesScope?.Dispose(); + ServiceProvider = null!; + _instanceServicesScope = null; + } + + internal class Core + { + internal required LifetimeStopwatch Stopwatch { get; init; } + internal string? Region { get; init; } + internal string? ExecutionEnvironment { get; init; } + internal string? FunctionName { get; init; } + internal int? FunctionMemorySize { get; init; } + internal string? FunctionVersion { get; init; } + internal string? InitializationType { get; init; } + internal string? LogGroupName { get; init; } + internal string? LogStreamName { get; init; } + internal string? TaskRoot { get; init; } + } +} diff --git a/src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs b/src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs new file mode 100644 index 00000000..26c3f5de --- /dev/null +++ b/src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs @@ -0,0 +1,45 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace MinimalLambda; + +internal class LambdaLifecycleContextFactory( + IServiceScopeFactory scopeFactory, + LifetimeStopwatch stopwatch, + IConfiguration configuration +) : ILambdaLifecycleContextFactory +{ + private LambdaLifecycleContext.Core? _contextCore; + + public ILambdaLifecycleContext Create( + IDictionary properties, + CancellationToken cancellationToken + ) + { + _contextCore ??= new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + Region = configuration["AWS_REGION"] ?? configuration["AWS_DEFAULT_REGION"], + ExecutionEnvironment = configuration["AWS_EXECUTION_ENV"], + FunctionName = configuration["AWS_LAMBDA_FUNCTION_NAME"], + FunctionMemorySize = int.TryParse( + configuration["AWS_LAMBDA_FUNCTION_MEMORY_SIZE"], + out var memorySize + ) + ? memorySize + : null, + FunctionVersion = configuration["AWS_LAMBDA_FUNCTION_VERSION"], + InitializationType = configuration["AWS_LAMBDA_INITIALIZATION_TYPE"], + LogGroupName = configuration["AWS_LAMBDA_LOG_GROUP_NAME"], + LogStreamName = configuration["AWS_LAMBDA_LOG_STREAM_NAME"], + TaskRoot = configuration["LAMBDA_TASK_ROOT"], + }; + + return new LambdaLifecycleContext( + _contextCore, + scopeFactory, + properties, + cancellationToken + ); + } +} From db7b8eaec0a5db426f8c7f9869d54b7e3a6a07a7 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 09:29:33 -0500 Subject: [PATCH 04/27] test(minimal-lambda): add unit tests for lifecycle context and factory - Added tests for `LambdaLifecycleContextFactory` to verify factory behavior and property resolution. - Added tests for `LambdaLifecycleContext` to confirm lazy initialization, property access, and resource disposal. - Validated configuration-based property initialization for Lambda environment variables. - Ensured context reusability and correctness across multiple calls. --- .../LambdaLifecycleContextFactoryTests.cs | 545 ++++++++++++++ .../Context/LambdaLifecycleContextTests.cs | 685 ++++++++++++++++++ 2 files changed, 1230 insertions(+) create mode 100644 tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextFactoryTests.cs create mode 100644 tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextTests.cs diff --git a/tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextFactoryTests.cs b/tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextFactoryTests.cs new file mode 100644 index 00000000..43a957c4 --- /dev/null +++ b/tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextFactoryTests.cs @@ -0,0 +1,545 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace MinimalLambda.UnitTests.Core.Context; + +[TestSubject(typeof(LambdaLifecycleContextFactory))] +public class LambdaLifecycleContextFactoryTests +{ + [Theory] + [AutoNSubstituteData] + internal void Constructor_WithValidDependencies_SuccessfullyConstructs( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch, + IConfiguration configuration + ) + { + // Act + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Assert + factory.Should().NotBeNull(); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReturnsLambdaLifecycleContext( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch, + IConfiguration configuration, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(properties, cancellationToken); + + // Assert + result.Should().NotBeNull(); + result.Should().BeAssignableTo(); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_PassesPropertiesAndCancellationTokenToContext( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch, + IConfiguration configuration + ) + { + // Arrange + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + var properties = new Dictionary { { "key", "value" } }; + var cancellationToken = new CancellationToken(); + + // Act + var result = factory.Create(properties, cancellationToken); + + // Assert + result.Properties.Should().BeSameAs(properties); + result.CancellationToken.Should().Be(cancellationToken); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsRegionFromAwsRegionConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary { { "AWS_REGION", "us-east-1" } }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.Region.Should().Be("us-east-1"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsRegionFromAwsDefaultRegionWhenAwsRegionNotSet( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_DEFAULT_REGION", "us-west-2" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.Region.Should().Be("us-west-2"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_PrefersAwsRegionOverAwsDefaultRegion( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_REGION", "us-east-1" }, + { "AWS_DEFAULT_REGION", "us-west-2" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.Region.Should().Be("us-east-1"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsExecutionEnvironmentFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_EXECUTION_ENV", "AWS_Lambda_dotnet8" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.ExecutionEnvironment.Should().Be("AWS_Lambda_dotnet8"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsFunctionNameFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_LAMBDA_FUNCTION_NAME", "my-lambda-function" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.FunctionName.Should().Be("my-lambda-function"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsFunctionMemorySizeFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "512" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.FunctionMemorySize.Should().Be(512); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReturnsNullForFunctionMemorySizeWhenNotParseable( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "not-a-number" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.FunctionMemorySize.Should().BeNull(); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsFunctionVersionFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_LAMBDA_FUNCTION_VERSION", "$LATEST" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.FunctionVersion.Should().Be("$LATEST"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsInitializationTypeFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_LAMBDA_INITIALIZATION_TYPE", "on-demand" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.InitializationType.Should().Be("on-demand"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsLogGroupNameFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_LAMBDA_LOG_GROUP_NAME", "/aws/lambda/my-function" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.LogGroupName.Should().Be("/aws/lambda/my-function"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsLogStreamNameFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_LAMBDA_LOG_STREAM_NAME", "2024/12/16/[$LATEST]abcdef123456" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.LogStreamName.Should().Be("2024/12/16/[$LATEST]abcdef123456"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReadsTaskRootFromConfiguration( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary { { "LAMBDA_TASK_ROOT", "/var/task" } }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.TaskRoot.Should().Be("/var/task"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_UsesStopwatchFromConstructor( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch, + IConfiguration configuration + ) + { + // Arrange + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + (result.ElapsedTime >= TimeSpan.Zero) + .Should() + .BeTrue(); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReusesContextCoreAcrossMultipleCalls( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_REGION", "us-east-1" }, + { "AWS_LAMBDA_FUNCTION_NAME", "my-function" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result1 = factory.Create(new Dictionary(), CancellationToken.None); + var result2 = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result1.Region.Should().Be("us-east-1"); + result2.Region.Should().Be("us-east-1"); + result1.FunctionName.Should().Be("my-function"); + result2.FunctionName.Should().Be("my-function"); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_ReturnsNullForUnconfiguredProperties( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configuration = new ConfigurationBuilder().Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.Region.Should().BeNull(); + result.ExecutionEnvironment.Should().BeNull(); + result.FunctionName.Should().BeNull(); + result.FunctionMemorySize.Should().BeNull(); + result.FunctionVersion.Should().BeNull(); + result.InitializationType.Should().BeNull(); + result.LogGroupName.Should().BeNull(); + result.LogStreamName.Should().BeNull(); + result.TaskRoot.Should().BeNull(); + } + + [Theory] + [AutoNSubstituteData] + internal void Create_WithAllConfigurationValues_PopulatesAllProperties( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch + ) + { + // Arrange + var configValues = new Dictionary + { + { "AWS_REGION", "us-east-1" }, + { "AWS_EXECUTION_ENV", "AWS_Lambda_dotnet8" }, + { "AWS_LAMBDA_FUNCTION_NAME", "my-lambda-function" }, + { "AWS_LAMBDA_FUNCTION_MEMORY_SIZE", "1024" }, + { "AWS_LAMBDA_FUNCTION_VERSION", "$LATEST" }, + { "AWS_LAMBDA_INITIALIZATION_TYPE", "provisioned-concurrency" }, + { "AWS_LAMBDA_LOG_GROUP_NAME", "/aws/lambda/my-function" }, + { "AWS_LAMBDA_LOG_STREAM_NAME", "2024/12/16/[$LATEST]abcdef123456" }, + { "LAMBDA_TASK_ROOT", "/var/task" }, + }; + var configuration = new ConfigurationBuilder().AddInMemoryCollection(configValues).Build(); + + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Act + var result = factory.Create(new Dictionary(), CancellationToken.None); + + // Assert + result.Region.Should().Be("us-east-1"); + result.ExecutionEnvironment.Should().Be("AWS_Lambda_dotnet8"); + result.FunctionName.Should().Be("my-lambda-function"); + result.FunctionMemorySize.Should().Be(1024); + result.FunctionVersion.Should().Be("$LATEST"); + result.InitializationType.Should().Be("provisioned-concurrency"); + result.LogGroupName.Should().Be("/aws/lambda/my-function"); + result.LogStreamName.Should().Be("2024/12/16/[$LATEST]abcdef123456"); + result.TaskRoot.Should().Be("/var/task"); + } + + [Theory] + [AutoNSubstituteData] + internal void FactoryImplementsILambdaLifecycleContextFactory( + IServiceScopeFactory serviceScopeFactory, + LifetimeStopwatch stopwatch, + IConfiguration configuration + ) + { + // Act + var factory = new LambdaLifecycleContextFactory( + serviceScopeFactory, + stopwatch, + configuration + ); + + // Assert + factory.Should().BeAssignableTo(); + } +} diff --git a/tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextTests.cs b/tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextTests.cs new file mode 100644 index 00000000..7bdb3309 --- /dev/null +++ b/tests/MinimalLambda.UnitTests/Core/Context/LambdaLifecycleContextTests.cs @@ -0,0 +1,685 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace MinimalLambda.UnitTests.Core.Context; + +[TestSubject(typeof(LambdaLifecycleContext))] +public class LambdaLifecycleContextTests +{ + [Theory] + [AutoNSubstituteData] + internal void Constructor_WithValidParameters_SuccessfullyConstructs( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + Region = "us-east-1", + }; + + // Act + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Assert + context.Should().NotBeNull(); + } + + [Theory] + [AutoNSubstituteData] + internal void CancellationToken_ReturnsCancellationTokenPassedToConstructor( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties + ) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + var expectedToken = new CancellationToken(); + + // Act + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + expectedToken + ); + + // Assert + context.CancellationToken.Should().Be(expectedToken); + } + + [Theory] + [AutoNSubstituteData] + internal void Properties_ReturnsPropertiesDictionaryPassedToConstructor( + IServiceScopeFactory serviceScopeFactory, + CancellationToken cancellationToken + ) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + var propertiesDict = new Dictionary + { + { "key1", "value1" }, + { "key2", 42 }, + }; + + // Act + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + propertiesDict, + cancellationToken + ); + + // Assert + context.Properties.Should().BeEquivalentTo(propertiesDict); + context.Properties.Should().BeSameAs(propertiesDict); + } + + [Theory] + [AutoNSubstituteData] + internal void ServiceProvider_IsCreatedOnFirstAccess(IServiceScopeFactory serviceScopeFactory) + { + // Arrange + var mockScope = Substitute.For(); + var mockServiceProvider = Substitute.For(); + mockScope.ServiceProvider.Returns(mockServiceProvider); + serviceScopeFactory.CreateScope().Returns(mockScope); + + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + + // Act + var result = context.ServiceProvider; + + // Assert + result.Should().NotBeNull(); + result.Should().BeSameAs(mockServiceProvider); + serviceScopeFactory.Received(1).CreateScope(); + } + + [Theory] + [AutoNSubstituteData] + internal void ServiceProvider_ReturnsSameScopeOnSubsequentAccess( + IServiceScopeFactory serviceScopeFactory + ) + { + // Arrange + var mockScope = Substitute.For(); + var mockServiceProvider = Substitute.For(); + mockScope.ServiceProvider.Returns(mockServiceProvider); + serviceScopeFactory.CreateScope().Returns(mockScope); + + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + + // Act + var result1 = context.ServiceProvider; + var result2 = context.ServiceProvider; + var result3 = context.ServiceProvider; + + // Assert + result1.Should().BeSameAs(result2); + result2.Should().BeSameAs(result3); + serviceScopeFactory.Received(1).CreateScope(); + } + + [Theory] + [AutoNSubstituteData] + internal void ElapsedTime_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.ElapsedTime; + + // Assert + (result >= TimeSpan.Zero) + .Should() + .BeTrue(); + } + + [Theory] + [AutoNSubstituteData] + internal void Region_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "us-west-2"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + Region = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.Region; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void ExecutionEnvironment_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "AWS_Lambda_dotnet8"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + ExecutionEnvironment = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.ExecutionEnvironment; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void FunctionName_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "my-lambda-function"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + FunctionName = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.FunctionName; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void FunctionMemorySize_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const int expectedValue = 512; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + FunctionMemorySize = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.FunctionMemorySize; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void FunctionVersion_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "$LATEST"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + FunctionVersion = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.FunctionVersion; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void InitializationType_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "on-demand"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + InitializationType = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.InitializationType; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void LogGroupName_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "/aws/lambda/my-function"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + LogGroupName = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.LogGroupName; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void LogStreamName_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "2024/12/16/[$LATEST]abcdef123456"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + LogStreamName = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.LogStreamName; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal void TaskRoot_ReturnsValueFromContextCore( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + const string expectedValue = "/var/task"; + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + TaskRoot = expectedValue, + }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Act + var result = context.TaskRoot; + + // Assert + result.Should().Be(expectedValue); + } + + [Theory] + [AutoNSubstituteData] + internal async Task DisposeAsync_DisposesServiceScopeWhenAsyncDisposable( + IServiceScopeFactory serviceScopeFactory + ) + { + // Arrange + var asyncDisposableScope = Substitute.For(); + var mockServiceProvider = Substitute.For(); + asyncDisposableScope.ServiceProvider.Returns(mockServiceProvider); + serviceScopeFactory.CreateScope().Returns(asyncDisposableScope); + + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + _ = context.ServiceProvider; // Trigger lazy initialization + + // Act + await context.DisposeAsync(); + + // Assert + await ((IAsyncDisposable)asyncDisposableScope).Received(1).DisposeAsync(); + } + + [Theory] + [AutoNSubstituteData] + internal async Task DisposeAsync_DisposesServiceScopeSynchronouslyWhenNotAsyncDisposable( + IServiceScopeFactory serviceScopeFactory + ) + { + // Arrange + var mockScope = Substitute.For(); + var mockServiceProvider = Substitute.For(); + mockScope.ServiceProvider.Returns(mockServiceProvider); + serviceScopeFactory.CreateScope().Returns(mockScope); + + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + _ = context.ServiceProvider; // Trigger lazy initialization + + // Act + await context.DisposeAsync(); + + // Assert + mockScope.Received(1).Dispose(); + } + + [Theory] + [AutoNSubstituteData] + internal async Task DisposeAsync_DoesNotDisposeIfServiceProviderNeverAccessed( + IServiceScopeFactory serviceScopeFactory + ) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + + // Act + await context.DisposeAsync(); + + // Assert + serviceScopeFactory.DidNotReceive().CreateScope(); + } + + [Theory] + [AutoNSubstituteData] + internal async Task DisposeAsync_CanBeCalledMultipleTimes( + IServiceScopeFactory serviceScopeFactory + ) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + + // Act + var act = async () => + { + await context.DisposeAsync(); + await context.DisposeAsync(); // Should not throw + }; + + // Assert + await act.Should().NotThrowAsync(); + } + + [Theory] + [AutoNSubstituteData] + internal void ContextImplementsIAsyncDisposable(IServiceScopeFactory serviceScopeFactory) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + // Act + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + + // Assert + context.Should().BeAssignableTo(); + } + + [Theory] + [AutoNSubstituteData] + internal void ContextImplementsILambdaLifecycleContext(IServiceScopeFactory serviceScopeFactory) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + // Act + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + new Dictionary(), + CancellationToken.None + ); + + // Assert + context.Should().BeAssignableTo(); + } + + [Theory] + [AutoNSubstituteData] + internal void MultipleContextInstances_AreIndependent(IServiceScopeFactory serviceScopeFactory) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore1 = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + Region = "us-east-1", + }; + var contextCore2 = new LambdaLifecycleContext.Core + { + Stopwatch = stopwatch, + Region = "us-west-2", + }; + + var properties1 = new Dictionary(); + var properties2 = new Dictionary(); + + // Act + var context1 = new LambdaLifecycleContext( + contextCore1, + serviceScopeFactory, + properties1, + CancellationToken.None + ); + var context2 = new LambdaLifecycleContext( + contextCore2, + serviceScopeFactory, + properties2, + CancellationToken.None + ); + + properties1["key"] = "value1"; + properties2["key"] = "value2"; + + // Assert + context1.Properties["key"].Should().Be("value1"); + context2.Properties["key"].Should().Be("value2"); + context1.Region.Should().Be("us-east-1"); + context2.Region.Should().Be("us-west-2"); + } + + [Theory] + [AutoNSubstituteData] + internal void NullableProperties_ReturnNullWhenNotSet( + IServiceScopeFactory serviceScopeFactory, + IDictionary properties, + CancellationToken cancellationToken + ) + { + // Arrange + var stopwatch = new LifetimeStopwatch(); + var contextCore = new LambdaLifecycleContext.Core { Stopwatch = stopwatch }; + + // Act + var context = new LambdaLifecycleContext( + contextCore, + serviceScopeFactory, + properties, + cancellationToken + ); + + // Assert + context.Region.Should().BeNull(); + context.ExecutionEnvironment.Should().BeNull(); + context.FunctionName.Should().BeNull(); + context.FunctionMemorySize.Should().BeNull(); + context.FunctionVersion.Should().BeNull(); + context.InitializationType.Should().BeNull(); + context.LogGroupName.Should().BeNull(); + context.LogStreamName.Should().BeNull(); + context.TaskRoot.Should().BeNull(); + } +} From 8a748253ac99e680c1a0b575f7c7ce9a722b72d0 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 10:20:16 -0500 Subject: [PATCH 05/27] feat(minimal-lambda): update Lambda initialization for enhanced lifecycle context support - Replaced `LambdaInitDelegate` with `LambdaInitDelegate2` to incorporate `ILambdaLifecycleContext`. - Added `ILambdaLifecycleContextFactory` and `ConcurrentDictionary` for init handler shared state. - Updated `DefaultLambdaOnInitBuilderFactory` and `LambdaOnInitBuilder` to support the new context. - Removed obsolete `OnInitClearLambdaOutputFormatting` method for cleanup and modernization. - Enhanced init handler building logic with context-aware execution. --- .../Builders/ILambdaOnInitBuilder.cs | 11 ++++-- .../Delegates/LambdaInitDelegate.cs | 2 + .../DefaultLambdaOnInitBuilderFactory.cs | 5 ++- .../Extensions/ServiceCollectionExtensions.cs | 1 + .../Builder/LambdaApplication.cs | 9 ++++- .../Builder/LambdaOnInitBuilder.cs | 33 ++++++++++------ ...utFormattingLambdaApplicationExtensions.cs | 39 ------------------- 7 files changed, 43 insertions(+), 57 deletions(-) delete mode 100644 src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs diff --git a/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs b/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs index f86f1e70..93b673ab 100644 --- a/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs +++ b/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs @@ -1,3 +1,5 @@ +using System.Collections.Concurrent; + namespace MinimalLambda.Builder; /// Builder for composing Lambda init handlers that execute during the Init phase. @@ -16,7 +18,10 @@ namespace MinimalLambda.Builder; public interface ILambdaOnInitBuilder { /// Gets the read-only list of registered Init handlers. - IReadOnlyList InitHandlers { get; } + IReadOnlyList InitHandlers { get; } + + /// Gets a dictionary for storing state that is shared across Init handlers. + ConcurrentDictionary Properties { get; } /// Gets the service provider for dependency injection. IServiceProvider Services { get; } @@ -24,7 +29,7 @@ public interface ILambdaOnInitBuilder /// Registers a handler to execute during the Lambda Init phase. /// The to register. /// The current instance for method chaining. - ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler); + ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler); /// Builds the final init delegate by composing all registered handlers. /// @@ -39,5 +44,5 @@ public interface ILambdaOnInitBuilder /// A function that accepts a and executes all registered /// handlers concurrently. Ready for the Lambda Init phase. /// - Func> Build(); + Func>? Build(); } diff --git a/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs b/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs index 8f55cd8a..3b224d46 100644 --- a/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs +++ b/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs @@ -16,3 +16,5 @@ public delegate Task LambdaInitDelegate( IServiceProvider services, CancellationToken cancellationToken ); + +public delegate Task LambdaInitDelegate2(ILambdaLifecycleContext context); diff --git a/src/MinimalLambda/Builder/DefaultLambdaOnInitBuilderFactory.cs b/src/MinimalLambda/Builder/DefaultLambdaOnInitBuilderFactory.cs index bde176c7..7e73887f 100644 --- a/src/MinimalLambda/Builder/DefaultLambdaOnInitBuilderFactory.cs +++ b/src/MinimalLambda/Builder/DefaultLambdaOnInitBuilderFactory.cs @@ -6,9 +6,10 @@ namespace MinimalLambda.Builder; internal class DefaultLambdaOnInitBuilderFactory( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) : ILambdaOnInitBuilderFactory { public ILambdaOnInitBuilder CreateBuilder() => - new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); + new LambdaOnInitBuilder(serviceProvider, scopeFactory, options, contextFactory); } diff --git a/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs b/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs index ec5fa000..3d555b2b 100644 --- a/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs +++ b/src/MinimalLambda/Builder/Extensions/ServiceCollectionExtensions.cs @@ -29,6 +29,7 @@ public IServiceCollection AddLambdaHostCoreServices() >(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); // Register internal Lambda execution components diff --git a/src/MinimalLambda/Builder/LambdaApplication.cs b/src/MinimalLambda/Builder/LambdaApplication.cs index 9f3f22e9..3e4a840b 100644 --- a/src/MinimalLambda/Builder/LambdaApplication.cs +++ b/src/MinimalLambda/Builder/LambdaApplication.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -111,10 +112,14 @@ Func middleware // └──────────────────────────────────────────────────────────┘ /// - public IReadOnlyList InitHandlers => _onInitBuilder.InitHandlers; + public IReadOnlyList InitHandlers => _onInitBuilder.InitHandlers; /// - public ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler) + ConcurrentDictionary ILambdaOnInitBuilder.Properties => + _onInitBuilder.Properties; + + /// + public ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler) { _onInitBuilder.OnInit(handler); return this; diff --git a/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs b/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs index 50a94ebd..3ef9df42 100644 --- a/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -5,30 +6,36 @@ namespace MinimalLambda.Builder; internal class LambdaOnInitBuilder : ILambdaOnInitBuilder { - private readonly IList _handlers = []; + private readonly IList _handlers = []; private readonly LambdaHostOptions _options; private readonly IServiceScopeFactory _scopeFactory; + private readonly ILambdaLifecycleContextFactory _contextFactory; public LambdaOnInitBuilder( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { ArgumentNullException.ThrowIfNull(serviceProvider); ArgumentNullException.ThrowIfNull(scopeFactory); ArgumentNullException.ThrowIfNull(options); + ArgumentNullException.ThrowIfNull(contextFactory); Services = serviceProvider; _scopeFactory = scopeFactory; _options = options.Value; + _contextFactory = contextFactory; } public IServiceProvider Services { get; } - public IReadOnlyList InitHandlers => _handlers.AsReadOnly(); + public ConcurrentDictionary Properties { get; } = new(); - public ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler) + public IReadOnlyList InitHandlers => _handlers.AsReadOnly(); + + public ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler) { ArgumentNullException.ThrowIfNull(handler); @@ -36,9 +43,9 @@ public ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler) return this; } - public Func> Build() => + public Func>? Build() => _handlers.Count == 0 - ? _ => Task.FromResult(true) + ? null : async Task (stoppingToken) => { using var cts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken); @@ -71,16 +78,20 @@ public Func> Build() => }; private async Task<(Exception? Error, bool ShouldContinue)> RunInitHandler( - LambdaInitDelegate handler, + LambdaInitDelegate2 handler, CancellationToken cancellationToken ) { try { - using var scope = _scopeFactory.CreateScope(); - var result = await handler(scope.ServiceProvider, cancellationToken) - .ConfigureAwait(false); - return (null, result); + var context = _contextFactory.Create(Properties, cancellationToken); + + await using (context as IAsyncDisposable) + { + using var scope = _scopeFactory.CreateScope(); + var result = await handler(context).ConfigureAwait(false); + return (null, result); + } } catch (Exception ex) { diff --git a/src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs b/src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs deleted file mode 100644 index 5e6c6ad1..00000000 --- a/src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace MinimalLambda.Builder; - -/// Provides extension methods for managing Lambda runtime output formatting. -public static class OutputFormattingLambdaApplicationExtensions -{ - /// Clears Lambda runtime output formatting and resets console output to standard behavior. - /// - /// The AWS Lambda runtime applies custom formatting to console output. This method resets the - /// console to use a standard with auto-flushing, which is essential - /// for structured logging frameworks like Serilog to output JSON without corruption. - /// - /// The Lambda application to configure. - /// The configured for method chaining. - public static ILambdaOnInitBuilder OnInitClearLambdaOutputFormatting( - this ILambdaOnInitBuilder application - ) - { - ArgumentNullException.ThrowIfNull(application); - - application.OnInit( - Task (services, _) => - { - var logger = services.GetService>(); - - // This will clear the output formatting set by the Lambda runtime. - Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true }); - - logger?.LogInformation("Clearing Lambda output formatting"); - - return Task.FromResult(true); - } - ); - - return application; - } -} From c7f14d22fbb4071c07345fa0162521d91e700763 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 12:20:16 -0500 Subject: [PATCH 06/27] feat(minimal-lambda): enhance lifecycle context and Lambda output formatting - Renamed `ParameterSource.Context` to `ParameterSource.HostContext` for improved clarity. - Added new `ParameterSource.LifecycleContext` and support for `ILambdaLifecycleContext`. - Introduced `OutputFormattingLambdaApplicationExtensions.OnInitClearLambdaOutputFormatting` for custom formatting. - Updated generators and handlers to improve usage of `HostContext` and `LifecycleContext`. - Enhanced DI for services, ensuring proper keyed and optional service resolution. - Improved error handling and timeout behavior during `OnInit` execution. - Updated `LifetimeStopwatch` to initialize automatically with application start. --- .../Properties/launchSettings.json | 3 +- .../GeneratorConstants.cs | 2 ++ .../Models/ParameterInfo.cs | 5 +-- .../Models/ParameterSource.cs | 3 +- .../OutputGenerators/GenericHandlerSources.cs | 14 +++++--- .../OutputGenerators/MapHandlerSources.cs | 2 +- .../SyntaxProviders/OnInitSyntaxProvider.cs | 3 +- .../Templates/GenericHandler.scriban | 2 +- .../Builder/LambdaApplication.cs | 2 +- .../Builder/LambdaOnInitBuilder.cs | 12 ++++++- ...utFormattingLambdaApplicationExtensions.cs | 36 +++++++++++++++++++ .../Core/Context/LifetimeStopwatch.cs | 2 +- src/MinimalLambda/MinimalLambda.csproj | 2 ++ .../Runtime/LambdaHostedService.cs | 2 +- ...llInputSources#LambdaHandler.g.verified.cs | 2 +- ...dLambdaContext#LambdaHandler.g.verified.cs | 2 +- ...bdaHostContext#LambdaHandler.g.verified.cs | 2 +- ..._ComplexOutput#LambdaHandler.g.verified.cs | 2 +- ...iKeyedServices#LambdaHandler.g.verified.cs | 2 +- 19 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs diff --git a/examples/MinimalLambda.Example.Lifecycle/Properties/launchSettings.json b/examples/MinimalLambda.Example.Lifecycle/Properties/launchSettings.json index a348821c..0059dfcb 100644 --- a/examples/MinimalLambda.Example.Lifecycle/Properties/launchSettings.json +++ b/examples/MinimalLambda.Example.Lifecycle/Properties/launchSettings.json @@ -7,7 +7,8 @@ "AWS_LAMBDA_RUNTIME_API": "localhost:5050", "DOTNET_ENVIRONMENT": "Development", "AWS_LAMBDA_LOG_FORMAT": "JSON", - "AWS_LAMBDA_LOG_LEVEL": "DEBUG" + "AWS_LAMBDA_LOG_LEVEL": "DEBUG", + "AWS_LAMBDA_FUNCTION_NAME": "MinimalLambda.Example.Lifecycle" } } } diff --git a/src/MinimalLambda.SourceGenerators/GeneratorConstants.cs b/src/MinimalLambda.SourceGenerators/GeneratorConstants.cs index 0ab2717f..92219875 100644 --- a/src/MinimalLambda.SourceGenerators/GeneratorConstants.cs +++ b/src/MinimalLambda.SourceGenerators/GeneratorConstants.cs @@ -7,6 +7,8 @@ internal static class TypeConstants internal const string ILambdaHostContext = "global::MinimalLambda.ILambdaHostContext"; + internal const string ILambdaLifecycleContext = "global::MinimalLambda.ILambdaLifecycleContext"; + internal const string CancellationToken = "global::System.Threading.CancellationToken"; internal const string Task = "global::System.Threading.Tasks.Task"; diff --git a/src/MinimalLambda.SourceGenerators/Models/ParameterInfo.cs b/src/MinimalLambda.SourceGenerators/Models/ParameterInfo.cs index 50ad63e1..f2290859 100644 --- a/src/MinimalLambda.SourceGenerators/Models/ParameterInfo.cs +++ b/src/MinimalLambda.SourceGenerators/Models/ParameterInfo.cs @@ -69,8 +69,9 @@ private static ( return type switch { TypeConstants.CancellationToken => (ParameterSource.CancellationToken, null), - TypeConstants.ILambdaContext => (ParameterSource.Context, null), - TypeConstants.ILambdaHostContext => (ParameterSource.Context, null), + TypeConstants.ILambdaContext => (ParameterSource.HostContext, null), + TypeConstants.ILambdaHostContext => (ParameterSource.HostContext, null), + TypeConstants.ILambdaLifecycleContext => (ParameterSource.LifecycleContext, null), _ => (ParameterSource.Service, null), }; } diff --git a/src/MinimalLambda.SourceGenerators/Models/ParameterSource.cs b/src/MinimalLambda.SourceGenerators/Models/ParameterSource.cs index 1aad9519..61315319 100644 --- a/src/MinimalLambda.SourceGenerators/Models/ParameterSource.cs +++ b/src/MinimalLambda.SourceGenerators/Models/ParameterSource.cs @@ -5,6 +5,7 @@ internal enum ParameterSource Event, KeyedService, CancellationToken, - Context, + HostContext, + LifecycleContext, Service, } diff --git a/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs b/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs index cb78475f..08236b17 100644 --- a/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs +++ b/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs @@ -129,22 +129,26 @@ private static HandlerArg[] BuildHandlerParameterAssignment(this DelegateInfo de Assignment = param.Source switch { // CancellationToken -> get directly from arguments - ParameterSource.CancellationToken => "cancellationToken", + ParameterSource.CancellationToken => "context.CancellationToken", + + // ILambdaLifecycleContext -> get directly from arguments + ParameterSource.LifecycleContext => "context", // inject keyed service from the DI container - required ParameterSource.KeyedService when param.IsRequired => - $"serviceProvider.GetRequiredKeyedService<{param.TypeInfo.FullyQualifiedType}>({param.KeyedServiceKey?.DisplayValue})", + $"context.ServiceProvider.GetRequiredKeyedService<{param.TypeInfo.FullyQualifiedType}>({param.KeyedServiceKey?.DisplayValue})", // inject keyed service from the DI container - optional ParameterSource.KeyedService => - $"serviceProvider.GetKeyedService<{param.TypeInfo.FullyQualifiedType}>({param.KeyedServiceKey?.DisplayValue})", + $"context.ServiceProvider.GetKeyedService<{param.TypeInfo.FullyQualifiedType}>({param.KeyedServiceKey?.DisplayValue})", // default: inject service from the DI container - required _ when param.IsRequired => - $"serviceProvider.GetRequiredService<{param.TypeInfo.FullyQualifiedType}>()", + $"context.ServiceProvider.GetRequiredService<{param.TypeInfo.FullyQualifiedType}>()", // default: inject service from the DI container - optional - _ => $"serviceProvider.GetService<{param.TypeInfo.FullyQualifiedType}>()", + _ => + $"context.ServiceProvider.GetService<{param.TypeInfo.FullyQualifiedType}>()", }, }) .ToArray(); diff --git a/src/MinimalLambda.SourceGenerators/OutputGenerators/MapHandlerSources.cs b/src/MinimalLambda.SourceGenerators/OutputGenerators/MapHandlerSources.cs index 323461f3..5a0cf96e 100644 --- a/src/MinimalLambda.SourceGenerators/OutputGenerators/MapHandlerSources.cs +++ b/src/MinimalLambda.SourceGenerators/OutputGenerators/MapHandlerSources.cs @@ -91,7 +91,7 @@ private static HandlerArg[] BuildHandlerParameterAssignment(this DelegateInfo de $"context.GetRequiredEvent<{param.TypeInfo.FullyQualifiedType}>()", // ILambdaContext OR ILambdaHostContext -> use context directly - ParameterSource.Context => "context", + ParameterSource.HostContext => "context", // CancellationToken -> get from context ParameterSource.CancellationToken => "context.CancellationToken", diff --git a/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnInitSyntaxProvider.cs b/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnInitSyntaxProvider.cs index c15e97ad..c94bcced 100644 --- a/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnInitSyntaxProvider.cs +++ b/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnInitSyntaxProvider.cs @@ -22,8 +22,7 @@ private static bool IsBaseOnShutdownCall(this DelegateInfo delegateInfo) => is { ReturnTypeInfo.FullyQualifiedType: TypeConstants.TaskBool, Parameters: [ - { TypeInfo.FullyQualifiedType: TypeConstants.IServiceProvider }, - { TypeInfo.FullyQualifiedType: TypeConstants.CancellationToken }, + { TypeInfo.FullyQualifiedType: TypeConstants.ILambdaLifecycleContext }, ], }; } diff --git a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban index acfbb6f0..fdb49485 100644 --- a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban +++ b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban @@ -23,7 +23,7 @@ namespace MinimalLambda.Generated return application.{{ name }}({{ name }}); - {{ if call.should_await ~}} async {{ end ~}}{{ call.wrapper_return_type }} {{ name }}(IServiceProvider serviceProvider, CancellationToken cancellationToken) + {{ if call.should_await ~}} async {{ end ~}}{{ call.wrapper_return_type }} {{ name }}(ILambdaLifecycleContext context) { {{~ if call.has_any_keyed_service_parameter ~}} if (serviceProvider.GetService() is not IServiceProviderIsKeyedService) diff --git a/src/MinimalLambda/Builder/LambdaApplication.cs b/src/MinimalLambda/Builder/LambdaApplication.cs index 3e4a840b..5c3297db 100644 --- a/src/MinimalLambda/Builder/LambdaApplication.cs +++ b/src/MinimalLambda/Builder/LambdaApplication.cs @@ -126,7 +126,7 @@ public ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler) } /// - Func> ILambdaOnInitBuilder.Build() => _onInitBuilder.Build(); + Func>? ILambdaOnInitBuilder.Build() => _onInitBuilder.Build(); // ┌──────────────────────────────────────────────────────────┐ // │ ILambdaOnShutdownBuilder │ diff --git a/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs b/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs index 3ef9df42..bb5b189c 100644 --- a/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs @@ -53,7 +53,17 @@ public ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler) var tasks = _handlers.Select(h => RunInitHandler(h, cts.Token)); - var results = await Task.WhenAll(tasks).ConfigureAwait(false); + (Exception? Error, bool ShouldContinue)[] results; + try + { + results = await Task.WhenAll(tasks).WaitAsync(cts.Token).ConfigureAwait(false); + } + catch (TaskCanceledException) when (cts.Token.IsCancellationRequested) + { + throw new OperationCanceledException( + "Running OnInit handlers did not complete within the allocated timeout period." + ); + } var (errors, shouldContinue) = results.Aggregate( (errors: new List(), shouldContinue: true), diff --git a/src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs b/src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs new file mode 100644 index 00000000..58ade079 --- /dev/null +++ b/src/MinimalLambda/Builder/OnInit/OutputFormattingLambdaApplicationExtensions.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.Logging; + +namespace MinimalLambda.Builder; + +/// Provides extension methods for managing Lambda runtime output formatting. +public static class OutputFormattingLambdaApplicationExtensions +{ + /// Clears Lambda runtime output formatting and resets console output to standard behavior. + /// + /// The AWS Lambda runtime applies custom formatting to console output. This method resets the + /// console to use a standard with auto-flushing, which is essential + /// for structured logging frameworks like Serilog to output JSON without corruption. + /// + /// The Lambda application to configure. + /// The configured for method chaining. + public static ILambdaOnInitBuilder OnInitClearLambdaOutputFormatting( + this ILambdaOnInitBuilder application + ) + { + ArgumentNullException.ThrowIfNull(application); + + application.OnInit( + (ILogger? logger = null) => + { + // This will clear the output formatting set by the Lambda runtime. + Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = true }); + + logger?.LogInformation("Clearing Lambda output formatting"); + + return Task.FromResult(true); + } + ); + + return application; + } +} diff --git a/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs b/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs index 4f19d4fb..5890fe37 100644 --- a/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs +++ b/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs @@ -4,7 +4,7 @@ namespace MinimalLambda; internal sealed class LifetimeStopwatch { - private readonly Stopwatch _stopwatch = new(); + private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); internal TimeSpan Elapsed { diff --git a/src/MinimalLambda/MinimalLambda.csproj b/src/MinimalLambda/MinimalLambda.csproj index 4c1e3202..8e40ee54 100644 --- a/src/MinimalLambda/MinimalLambda.csproj +++ b/src/MinimalLambda/MinimalLambda.csproj @@ -11,6 +11,7 @@ MinimalLambda Minimal API-style framework for AWS Lambda functions README.md + $(InterceptorsNamespaces);MinimalLambda.Generated @@ -37,6 +38,7 @@ diff --git a/src/MinimalLambda/Runtime/LambdaHostedService.cs b/src/MinimalLambda/Runtime/LambdaHostedService.cs index c1ccd572..a15fef62 100644 --- a/src/MinimalLambda/Runtime/LambdaHostedService.cs +++ b/src/MinimalLambda/Runtime/LambdaHostedService.cs @@ -153,7 +153,7 @@ public async Task StopAsync(CancellationToken cancellationToken) /// Executes the Lambda hosting environment startup sequence. private async Task ExecuteAsync( Func> handler, - Func> initializer, + Func>? initializer, CancellationToken stoppingToken ) { diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs index 8216dce2..e1f72688 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs @@ -68,7 +68,7 @@ Task InvocationDelegate(ILambdaHostContext context) } // ParameterInfo { Type = string, Name = request, Source = Event, IsNullable = False, IsOptional = False} var arg0 = context.GetRequiredEvent(); - // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = context, Source = Context, IsNullable = False, IsOptional = False} + // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = context, Source = HostContext, IsNullable = False, IsOptional = False} var arg1 = context; // ParameterInfo { Type = global::System.Threading.CancellationToken, Name = cancellationToken, Source = CancellationToken, IsNullable = False, IsOptional = False} var arg2 = context.CancellationToken; diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs index b5a09837..6f330d17 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs @@ -64,7 +64,7 @@ Task InvocationDelegate(ILambdaHostContext context) { // ParameterInfo { Type = global::System.Threading.CancellationToken, Name = ct, Source = CancellationToken, IsNullable = False, IsOptional = False} var arg0 = context.CancellationToken; - // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = ctx, Source = Context, IsNullable = False, IsOptional = False} + // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = ctx, Source = HostContext, IsNullable = False, IsOptional = False} var arg1 = context; var response = castHandler.Invoke(arg0, arg1); if (context.Features.Get() is not IResponseFeature responseFeature) diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs index 9dcd01b5..8e8104ef 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs @@ -64,7 +64,7 @@ Task InvocationDelegate(ILambdaHostContext context) { // ParameterInfo { Type = global::System.Threading.CancellationToken, Name = ct, Source = CancellationToken, IsNullable = False, IsOptional = False} var arg0 = context.CancellationToken; - // ParameterInfo { Type = global::MinimalLambda.ILambdaHostContext, Name = ctx, Source = Context, IsNullable = False, IsOptional = False} + // ParameterInfo { Type = global::MinimalLambda.ILambdaHostContext, Name = ctx, Source = HostContext, IsNullable = False, IsOptional = False} var arg1 = context; var response = castHandler.Invoke(arg0, arg1); if (context.Features.Get() is not IResponseFeature responseFeature) diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs index 375863a3..92249518 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs @@ -71,7 +71,7 @@ async Task InvocationDelegate(ILambdaHostContext context) var arg0 = context.GetRequiredEvent(); // ParameterInfo { Type = global::IService, Name = service, Source = Service, IsNullable = False, IsOptional = False} var arg1 = context.ServiceProvider.GetRequiredService(); - // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = context, Source = Context, IsNullable = False, IsOptional = False} + // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = context, Source = HostContext, IsNullable = False, IsOptional = False} var arg2 = context; var response = await castHandler.Invoke(arg0, arg1, arg2); if (context.Features.Get() is not IResponseFeature responseFeature) diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs index 6fd88e89..079b4daa 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs @@ -73,7 +73,7 @@ Task InvocationDelegate(ILambdaHostContext context) } // ParameterInfo { Type = string, Name = input, Source = Event, IsNullable = False, IsOptional = False} var arg0 = context.GetRequiredEvent(); - // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = context, Source = Context, IsNullable = False, IsOptional = False} + // ParameterInfo { Type = global::Amazon.Lambda.Core.ILambdaContext, Name = context, Source = HostContext, IsNullable = False, IsOptional = False} var arg1 = context; // ParameterInfo { Type = global::IService, Name = service, Source = KeyedService, IsNullable = False, IsOptional = False, KeyedServiceKeyInfo { DisplayValue = "key", Type = string, BaseType = object } } var arg2 = context.ServiceProvider.GetRequiredKeyedService("key"); From 2b141cd5ca4fb1e0ebfd6e9160bbff3be2f3aa56 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 12:31:50 -0500 Subject: [PATCH 07/27] feat(source-generators): refactor handler cast generation logic - Replaced `BuildHandlerSignature` with a new `BuildHandlerCastCall` method for improved clarity. - Updated `GenericHandler.scriban` to adapt to the new handler cast generation process. - Added a new `Cast` helper method for safer and more explicit casting of delegate handlers. - Enhanced `BuildHandlerCastCall` to generate handler cast calls with detailed parameter and type info. --- .../Extensions/DelegateInfoExtensions.cs | 29 +++++++++++++++++++ .../OutputGenerators/GenericHandlerSources.cs | 2 +- .../Templates/GenericHandler.scriban | 4 ++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/MinimalLambda.SourceGenerators/Extensions/DelegateInfoExtensions.cs b/src/MinimalLambda.SourceGenerators/Extensions/DelegateInfoExtensions.cs index 62c2d14b..b2355feb 100644 --- a/src/MinimalLambda.SourceGenerators/Extensions/DelegateInfoExtensions.cs +++ b/src/MinimalLambda.SourceGenerators/Extensions/DelegateInfoExtensions.cs @@ -44,4 +44,33 @@ internal static string BuildHandlerSignature(this DelegateInfo delegateInfo) return handlerSignature; } + + extension(DelegateInfo delegateInfo) + { + internal string BuildHandlerCastCall() + { + var signatureBuilder = new StringBuilder(); + signatureBuilder.Append("Cast(handler, "); + + signatureBuilder.Append(delegateInfo.ReturnTypeInfo.FullyQualifiedType); + + signatureBuilder.Append(" ("); + + signatureBuilder.Append( + string.Join( + ", ", + delegateInfo.Parameters.Select( + (p, i) => + $"{p.TypeInfo.FullyQualifiedType} arg{i}{(p.IsOptional ? " = default" : "")}" + ) + ) + ); + + signatureBuilder.Append(") => throw null!)"); + + var handlerSignature = signatureBuilder.ToString(); + + return handlerSignature; + } + } } diff --git a/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs b/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs index 08236b17..a14df034 100644 --- a/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs +++ b/src/MinimalLambda.SourceGenerators/OutputGenerators/GenericHandlerSources.cs @@ -40,7 +40,7 @@ string generatedCodeAttribute .Select(higherOrderMethodInfo => { // build handler function signature - var handlerSignature = higherOrderMethodInfo.DelegateInfo.BuildHandlerSignature(); + var handlerSignature = higherOrderMethodInfo.DelegateInfo.BuildHandlerCastCall(); // get arguments for handler var handlerArgs = diff --git a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban index fdb49485..3a547f54 100644 --- a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban +++ b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban @@ -19,7 +19,7 @@ namespace MinimalLambda.Generated Delegate handler ) { - var castHandler = ({{ call.handler_signature }})handler; + var castHandler = {{ call.handler_signature }}; return application.{{ name }}({{ name }}); @@ -51,5 +51,7 @@ namespace MinimalLambda.Generated {{~ end ~}} {{~ end ~}} + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file From 807f2274586fabe6ec795b73f2eb3537a756fa7a Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 12:32:09 -0500 Subject: [PATCH 08/27] fix(unit-tests): make `OnInit` handler argument optional in tests - Updated `OnInit` lambda argument to allow `IService? y` defaulting to `null` in unit tests. --- .../VerifyTests/OnInitVerifyTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs index f4ba93ca..f3c2861a 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs @@ -218,7 +218,7 @@ await GeneratorTestHelpers.Verify( var lambda = builder.Build(); lambda.OnInit( - Task (string? x, IService? y) => + Task (string? x, IService? y = null) => { return Task.FromResult(true); } From 5ed353296234e06f16fce22af636b720fbb2eecc Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 12:46:25 -0500 Subject: [PATCH 09/27] feat(source-generators): refactor `OnInit` handling with `ILambdaLifecycleContext` - Updated `OnInit` handler methods to replace `IServiceProvider` with `ILambdaLifecycleContext` parameter. - Updated `GenericHandler.scriban` to leverage lifecycle context for service resolution. - Introduced `Cast` helper for safer and more explicit delegate casting across handlers. - Enhanced generated code to improve readability and maintainability by abstracting casting logic. - Adjusted unit tests to align with new `ILambdaLifecycleContext` usage and verify correctness. --- .../Templates/GenericHandler.scriban | 2 +- ...eturnTypeAsync#LambdaHandler.g.verified.cs | 6 +++-- ...ler_AsyncAndDi#LambdaHandler.g.verified.cs | 8 ++++--- ...UnexpectedType#LambdaHandler.g.verified.cs | 8 ++++--- ...odHandler_NoDi#LambdaHandler.g.verified.cs | 6 +++-- ..._MultipleCalls#LambdaHandler.g.verified.cs | 22 ++++++++++--------- ...Input_NoOutput#LambdaHandler.g.verified.cs | 6 +++-- ...eturnAsyncBool#LambdaHandler.g.verified.cs | 6 +++-- ...put_ReturnBool#LambdaHandler.g.verified.cs | 6 +++-- ...otExpectedType#LambdaHandler.g.verified.cs | 6 +++-- ...ectedTypeAsync#LambdaHandler.g.verified.cs | 6 +++-- ...pectedTypeTask#LambdaHandler.g.verified.cs | 6 +++-- ...ReturnTaskBool#LambdaHandler.g.verified.cs | 6 +++-- ...eferenceInputs#LambdaHandler.g.verified.cs | 14 +++++++----- ...bleKindOfInput#LambdaHandler.g.verified.cs | 18 ++++++++------- ...PrimitiveInput#LambdaHandler.g.verified.cs | 10 +++++---- .../VerifyTests/OnInitVerifyTests.cs | 2 +- 17 files changed, 84 insertions(+), 54 deletions(-) diff --git a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban index 3a547f54..a2551418 100644 --- a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban +++ b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban @@ -26,7 +26,7 @@ namespace MinimalLambda.Generated {{ if call.should_await ~}} async {{ end ~}}{{ call.wrapper_return_type }} {{ name }}(ILambdaLifecycleContext context) { {{~ if call.has_any_keyed_service_parameter ~}} - if (serviceProvider.GetService() is not IServiceProviderIsKeyedService) + if (context.ServiceProvider.GetService() is not IServiceProviderIsKeyedService) { throw new InvalidOperationException($"Unable to resolve service referenced by {nameof(FromKeyedServicesAttribute)}. The service provider doesn't support keyed services."); } diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs index c40732b9..be774481 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs index e470c3e7..e8e633fc 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs @@ -46,17 +46,19 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (global::IService arg0) => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { // ParameterInfo { Type = global::IService, Name = service, Source = Service, IsNullable = False, IsOptional = False} - var arg0 = serviceProvider.GetRequiredService(); + var arg0 = context.ServiceProvider.GetRequiredService(); var response = castHandler.Invoke(arg0); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs index 0645999b..e0cf07b7 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs @@ -46,17 +46,19 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (global::IService arg0) => throw null!); return application.OnInit(OnInit); - async Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + async Task OnInit(ILambdaLifecycleContext context) { // ParameterInfo { Type = global::IService, Name = service, Source = Service, IsNullable = False, IsOptional = False} - var arg0 = serviceProvider.GetRequiredService(); + var arg0 = context.ServiceProvider.GetRequiredService(); await castHandler.Invoke(arg0); return true; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs index 0cbeee79..e11612fd 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs index 56bbbaac..69f8a6b6 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs @@ -46,11 +46,11 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return response; @@ -64,16 +64,16 @@ internal static ILambdaOnInitBuilder OnInitInterceptor1( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string? arg0, global::IService? arg1) => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { // ParameterInfo { Type = string?, Name = x, Source = Service, IsNullable = True, IsOptional = False} - var arg0 = serviceProvider.GetService(); + var arg0 = context.ServiceProvider.GetService(); // ParameterInfo { Type = global::IService?, Name = y, Source = Service, IsNullable = True, IsOptional = False} - var arg1 = serviceProvider.GetService(); + var arg1 = context.ServiceProvider.GetService(); var response = castHandler.Invoke(arg0, arg1); return response; } @@ -86,19 +86,21 @@ internal static ILambdaOnInitBuilder OnInitInterceptor2( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string arg0, int arg1) => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { // ParameterInfo { Type = string, Name = x, Source = Service, IsNullable = False, IsOptional = False} - var arg0 = serviceProvider.GetRequiredService(); + var arg0 = context.ServiceProvider.GetRequiredService(); // ParameterInfo { Type = int, Name = y, Source = Service, IsNullable = False, IsOptional = False} - var arg1 = serviceProvider.GetRequiredService(); + var arg1 = context.ServiceProvider.GetRequiredService(); var response = castHandler.Invoke(arg0, arg1); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs index 6c745345..48303344 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Action)handler; + var castHandler = Cast(handler, void () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { castHandler.Invoke(); return Task.FromResult(true); } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs index e10e3849..04368d31 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs index c188896d..dedf0c34 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, bool () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return Task.FromResult(response); } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs index 3b79131d..44a29c5b 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, string () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { castHandler.Invoke(); return Task.FromResult(true); } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs index 6f5180f3..d8d02a84 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnInit(OnInit); - async Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + async Task OnInit(ILambdaLifecycleContext context) { await castHandler.Invoke(); return true; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs index f5f0bdca..f720cab1 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnInit(OnInit); - async Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + async Task OnInit(ILambdaLifecycleContext context) { await castHandler.Invoke(); return true; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs index f49bbb7e..e3ab2f89 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs index 4d54b558..459deb25 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs @@ -40,25 +40,27 @@ namespace MinimalLambda.Generated file static class GeneratedLambdaOnInitBuilderExtensions { // Location: InputFile.cs(10,8) - [InterceptsLocation(1, "dsRnyqNCGlvINFkBECwmUs0AAABJbnB1dEZpbGUuY3M=")] + [InterceptsLocation(1, "dITS7/hnxk7n1XWH1BHx4s0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string? arg0, global::IService? arg1 = default) => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { // ParameterInfo { Type = string?, Name = x, Source = Service, IsNullable = True, IsOptional = False} - var arg0 = serviceProvider.GetService(); - // ParameterInfo { Type = global::IService?, Name = y, Source = Service, IsNullable = True, IsOptional = False} - var arg1 = serviceProvider.GetService(); + var arg0 = context.ServiceProvider.GetService(); + // ParameterInfo { Type = global::IService?, Name = y, Source = Service, IsNullable = True, IsOptional = True} + var arg1 = context.ServiceProvider.GetService(); var response = castHandler.Invoke(arg0, arg1); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs index 5039e172..be02d8fd 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs @@ -46,29 +46,31 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (global::System.Threading.CancellationToken arg0, global::IService arg1, global::IService? arg2, global::IService arg3, global::IService? arg4) => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { - if (serviceProvider.GetService() is not IServiceProviderIsKeyedService) + if (context.ServiceProvider.GetService() is not IServiceProviderIsKeyedService) { throw new InvalidOperationException($"Unable to resolve service referenced by {nameof(FromKeyedServicesAttribute)}. The service provider doesn't support keyed services."); } // ParameterInfo { Type = global::System.Threading.CancellationToken, Name = token, Source = CancellationToken, IsNullable = False, IsOptional = False} - var arg0 = cancellationToken; + var arg0 = context.CancellationToken; // ParameterInfo { Type = global::IService, Name = service1, Source = KeyedService, IsNullable = False, IsOptional = False, KeyedServiceKeyInfo { DisplayValue = "key1", Type = string, BaseType = object } } - var arg1 = serviceProvider.GetRequiredKeyedService("key1"); + var arg1 = context.ServiceProvider.GetRequiredKeyedService("key1"); // ParameterInfo { Type = global::IService?, Name = service2, Source = KeyedService, IsNullable = True, IsOptional = False, KeyedServiceKeyInfo { DisplayValue = "key2", Type = string, BaseType = object } } - var arg2 = serviceProvider.GetKeyedService("key2"); + var arg2 = context.ServiceProvider.GetKeyedService("key2"); // ParameterInfo { Type = global::IService, Name = service3, Source = Service, IsNullable = False, IsOptional = False} - var arg3 = serviceProvider.GetRequiredService(); + var arg3 = context.ServiceProvider.GetRequiredService(); // ParameterInfo { Type = global::IService?, Name = service4, Source = Service, IsNullable = True, IsOptional = False} - var arg4 = serviceProvider.GetService(); + var arg4 = context.ServiceProvider.GetService(); var response = castHandler.Invoke(arg0, arg1, arg2, arg3, arg4); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs index c78843c8..cadd85a3 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs @@ -46,19 +46,21 @@ internal static ILambdaOnInitBuilder OnInitInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string arg0, int arg1) => throw null!); return application.OnInit(OnInit); - Task OnInit(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnInit(ILambdaLifecycleContext context) { // ParameterInfo { Type = string, Name = x, Source = Service, IsNullable = False, IsOptional = False} - var arg0 = serviceProvider.GetRequiredService(); + var arg0 = context.ServiceProvider.GetRequiredService(); // ParameterInfo { Type = int, Name = y, Source = Service, IsNullable = False, IsOptional = False} - var arg1 = serviceProvider.GetRequiredService(); + var arg1 = context.ServiceProvider.GetRequiredService(); var response = castHandler.Invoke(arg0, arg1); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs index f3c2861a..90d7e8f9 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnInitVerifyTests.cs @@ -15,7 +15,7 @@ await GeneratorTestHelpers.Verify( var lambda = builder.Build(); lambda.OnInit( - async (services, token) => + async (context) => { return true; } From 4538693ce4966fd565cc02005b72054bccdbaed5 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 12:48:02 -0500 Subject: [PATCH 10/27] feat(minimal-lambda): unify `LambdaInitDelegate` with `ILambdaLifecycleContext` - Replaced `IServiceProvider` and `CancellationToken` parameters in `LambdaInitDelegate` with `ILambdaLifecycleContext`. - Simplified `LambdaInitDelegate` definition for improved usage consistency during the Function Init phase. --- .../Delegates/LambdaInitDelegate.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs b/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs index 3b224d46..0165123d 100644 --- a/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs +++ b/src/MinimalLambda.Abstractions/Delegates/LambdaInitDelegate.cs @@ -4,17 +4,14 @@ namespace MinimalLambda; /// A callback delegate invoked during the AWS Lambda Function Init phase, before any handler /// invocation. /// -/// A scoped for resolving dependencies. -/// Signals the handler to stop during the Function Init phase. +/// +/// The providing access to the scoped +/// and for the Function Init phase. +/// /// /// A that completes with true to allow the Function Init /// phase to continue, or false to abort the Function Init phase. Exceptions thrown are /// collected and rethrown after all delegates complete. /// /// -public delegate Task LambdaInitDelegate( - IServiceProvider services, - CancellationToken cancellationToken -); - -public delegate Task LambdaInitDelegate2(ILambdaLifecycleContext context); +public delegate Task LambdaInitDelegate(ILambdaLifecycleContext context); From 838d7834c6573134238fe6548b61f4a2fa7a60fb Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 13:29:11 -0500 Subject: [PATCH 11/27] refactor(minimal-lambda): replace `LambdaInitDelegate2` with `LambdaInitDelegate` - Standardized usage of `LambdaInitDelegate` across initialization handlers. - Updated `ILambdaOnInitBuilder`, `LambdaOnInitBuilder`, and `LambdaApplication` implementation. - Simplified init handler logic for consistency and easier maintenance. --- .../Builders/ILambdaOnInitBuilder.cs | 4 ++-- src/MinimalLambda/Builder/LambdaApplication.cs | 4 ++-- src/MinimalLambda/Builder/LambdaOnInitBuilder.cs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs b/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs index 93b673ab..2bc508b6 100644 --- a/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs +++ b/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs @@ -18,7 +18,7 @@ namespace MinimalLambda.Builder; public interface ILambdaOnInitBuilder { /// Gets the read-only list of registered Init handlers. - IReadOnlyList InitHandlers { get; } + IReadOnlyList InitHandlers { get; } /// Gets a dictionary for storing state that is shared across Init handlers. ConcurrentDictionary Properties { get; } @@ -29,7 +29,7 @@ public interface ILambdaOnInitBuilder /// Registers a handler to execute during the Lambda Init phase. /// The to register. /// The current instance for method chaining. - ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler); + ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler); /// Builds the final init delegate by composing all registered handlers. /// diff --git a/src/MinimalLambda/Builder/LambdaApplication.cs b/src/MinimalLambda/Builder/LambdaApplication.cs index 5c3297db..d36a988f 100644 --- a/src/MinimalLambda/Builder/LambdaApplication.cs +++ b/src/MinimalLambda/Builder/LambdaApplication.cs @@ -112,14 +112,14 @@ Func middleware // └──────────────────────────────────────────────────────────┘ /// - public IReadOnlyList InitHandlers => _onInitBuilder.InitHandlers; + public IReadOnlyList InitHandlers => _onInitBuilder.InitHandlers; /// ConcurrentDictionary ILambdaOnInitBuilder.Properties => _onInitBuilder.Properties; /// - public ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler) + public ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler) { _onInitBuilder.OnInit(handler); return this; diff --git a/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs b/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs index bb5b189c..1bc1dceb 100644 --- a/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaOnInitBuilder.cs @@ -6,7 +6,7 @@ namespace MinimalLambda.Builder; internal class LambdaOnInitBuilder : ILambdaOnInitBuilder { - private readonly IList _handlers = []; + private readonly IList _handlers = []; private readonly LambdaHostOptions _options; private readonly IServiceScopeFactory _scopeFactory; private readonly ILambdaLifecycleContextFactory _contextFactory; @@ -33,9 +33,9 @@ ILambdaLifecycleContextFactory contextFactory public ConcurrentDictionary Properties { get; } = new(); - public IReadOnlyList InitHandlers => _handlers.AsReadOnly(); + public IReadOnlyList InitHandlers => _handlers.AsReadOnly(); - public ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler) + public ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler) { ArgumentNullException.ThrowIfNull(handler); @@ -88,7 +88,7 @@ public ILambdaOnInitBuilder OnInit(LambdaInitDelegate2 handler) }; private async Task<(Exception? Error, bool ShouldContinue)> RunInitHandler( - LambdaInitDelegate2 handler, + LambdaInitDelegate handler, CancellationToken cancellationToken ) { From 8332593dc0ddf26a55b73eabe4dc70cc3c54d581 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 14:19:21 -0500 Subject: [PATCH 12/27] feat(minimal-lambda): introduce `ILifetimeStopwatch` and refactor lifecycle services - Added `ILifetimeStopwatch` interface to abstract lifetime tracking functionality. - Updated `LifetimeStopwatch` to implement `ILifetimeStopwatch` for consistency and extensibility. - Replaced direct `LifetimeStopwatch` references with `ILifetimeStopwatch` in lifecycle services and factories. - Registered `ILifetimeStopwatch` as a singleton in relevant DI configurations. - Refactored test cases to align with the interface abstraction and validate the updated behavior. --- .../Builder/LambdaApplicationBuilder.cs | 2 +- .../Core/Context/ILifetimeStopwatch.cs | 6 + .../Core/Context/LambdaLifecycleContext.cs | 2 +- .../Context/LambdaLifecycleContextFactory.cs | 2 +- .../Core/Context/LifetimeStopwatch.cs | 4 +- .../DefaultLambdaOnInitBuilderFactoryTests.cs | 20 +- ...dlewareLambdaApplicationExtensionsTests.cs | 1 + .../ServiceCollectionExtensionsTests.cs | 2 +- .../Builder/LambdaApplicationBuilderTests.cs | 10 +- .../Builder/LambdaApplicationTests.cs | 11 +- .../Builder/LambdaOnInitBuilderTests.cs | 220 +++++++++++++----- ...mattingLambdaApplicationExtensionsTests.cs | 1 + 12 files changed, 198 insertions(+), 83 deletions(-) create mode 100644 src/MinimalLambda/Core/Context/ILifetimeStopwatch.cs diff --git a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs index 07587991..66a4f15c 100644 --- a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs @@ -99,7 +99,7 @@ internal LambdaApplicationBuilder(LambdaApplicationOptions? settings) // Register core services that are required for Lambda Host to run Services.AddLambdaHostCoreServices(); - Services.AddSingleton(lifetimeStopwatch); + Services.AddSingleton(lifetimeStopwatch); } /// diff --git a/src/MinimalLambda/Core/Context/ILifetimeStopwatch.cs b/src/MinimalLambda/Core/Context/ILifetimeStopwatch.cs new file mode 100644 index 00000000..7d5262a4 --- /dev/null +++ b/src/MinimalLambda/Core/Context/ILifetimeStopwatch.cs @@ -0,0 +1,6 @@ +namespace MinimalLambda; + +internal interface ILifetimeStopwatch +{ + TimeSpan Elapsed { get; } +} diff --git a/src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs b/src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs index b341db7d..3b532ffc 100644 --- a/src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs +++ b/src/MinimalLambda/Core/Context/LambdaLifecycleContext.cs @@ -53,7 +53,7 @@ public async ValueTask DisposeAsync() internal class Core { - internal required LifetimeStopwatch Stopwatch { get; init; } + internal required ILifetimeStopwatch Stopwatch { get; init; } internal string? Region { get; init; } internal string? ExecutionEnvironment { get; init; } internal string? FunctionName { get; init; } diff --git a/src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs b/src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs index 26c3f5de..247f6aa8 100644 --- a/src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs +++ b/src/MinimalLambda/Core/Context/LambdaLifecycleContextFactory.cs @@ -5,7 +5,7 @@ namespace MinimalLambda; internal class LambdaLifecycleContextFactory( IServiceScopeFactory scopeFactory, - LifetimeStopwatch stopwatch, + ILifetimeStopwatch stopwatch, IConfiguration configuration ) : ILambdaLifecycleContextFactory { diff --git a/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs b/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs index 5890fe37..4634884e 100644 --- a/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs +++ b/src/MinimalLambda/Core/Context/LifetimeStopwatch.cs @@ -2,11 +2,11 @@ namespace MinimalLambda; -internal sealed class LifetimeStopwatch +internal sealed class LifetimeStopwatch : ILifetimeStopwatch { private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); - internal TimeSpan Elapsed + public TimeSpan Elapsed { get { diff --git a/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnInitBuilderFactoryTests.cs b/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnInitBuilderFactoryTests.cs index d58a0a29..8a4a664d 100644 --- a/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnInitBuilderFactoryTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnInitBuilderFactoryTests.cs @@ -12,21 +12,27 @@ public class DefaultLambdaOnInitBuilderFactoryTests private readonly IServiceScopeFactory _scopeFactory = Substitute.For(); private readonly IServiceProvider _serviceProvider = Substitute.For(); + private readonly ILambdaLifecycleContextFactory _contextFactory = + Substitute.For(); + [Theory] [InlineData(0)] // ServiceProvider [InlineData(1)] // ScopeFactory [InlineData(2)] // Options + [InlineData(3)] // ContextFactory public void CreateBuilder_WithNullParameter_ThrowsArgumentNullException(int parameterIndex) { // Arrange var serviceProvider = parameterIndex == 0 ? null : _serviceProvider; var scopeFactory = parameterIndex == 1 ? null : _scopeFactory; var options = parameterIndex == 2 ? null : _options; + var contextFactory = parameterIndex == 3 ? null : _contextFactory; var factory = new DefaultLambdaOnInitBuilderFactory( serviceProvider!, scopeFactory!, - options! + options!, + contextFactory! ); // Act & Assert - validation happens in LambdaOnInitBuilder constructor @@ -41,7 +47,8 @@ public void Constructor_WithValidParameters_SuccessfullyConstructs() var factory = new DefaultLambdaOnInitBuilderFactory( _serviceProvider, _scopeFactory, - _options + _options, + _contextFactory ); // Assert @@ -55,7 +62,8 @@ public void CreateBuilder_ReturnsLambdaOnInitBuilder() var factory = new DefaultLambdaOnInitBuilderFactory( _serviceProvider, _scopeFactory, - _options + _options, + _contextFactory ); // Act @@ -73,7 +81,8 @@ public void CreateBuilder_PassesServiceProviderToBuilder() var factory = new DefaultLambdaOnInitBuilderFactory( _serviceProvider, _scopeFactory, - _options + _options, + _contextFactory ); // Act @@ -90,7 +99,8 @@ public void CreateBuilder_CreatesNewInstanceEachCall() var factory = new DefaultLambdaOnInitBuilderFactory( _serviceProvider, _scopeFactory, - _options + _options, + _contextFactory ); // Act diff --git a/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs index b886bc25..45145823 100644 --- a/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs @@ -14,6 +14,7 @@ private static IHost CreateHostWithServices() services.ConfigureLambdaHostOptions(_ => { }); services.AddLambdaHostCoreServices(); services.TryAddLambdaHostDefaultServices(); + services.AddSingleton(); }); return builder.Build(); diff --git a/tests/MinimalLambda.UnitTests/Builder/Extensions/ServiceCollectionExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/Extensions/ServiceCollectionExtensionsTests.cs index f38be37c..a8760cbe 100644 --- a/tests/MinimalLambda.UnitTests/Builder/Extensions/ServiceCollectionExtensionsTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/Extensions/ServiceCollectionExtensionsTests.cs @@ -31,7 +31,7 @@ public void AddLambdaHostCoreServices_WithValidServiceCollection_ReturnsServiceC } [Theory] - [InlineData(13)] + [InlineData(14)] public void AddLambdaHostCoreServices_RegistersExactlyNServices(int servicesCount) { // Arrange diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs index d43642b6..dc3b5c76 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs @@ -297,8 +297,8 @@ public void Build_ConfigureOnInitBuilderCallback_AppliesInitHandlers() var app = builder.Build(); // Register init handlers on the app - LambdaInitDelegate handler1 = (_, _) => Task.FromResult(true); - LambdaInitDelegate handler2 = (_, _) => Task.FromResult(false); + LambdaInitDelegate handler1 = _ => Task.FromResult(true); + LambdaInitDelegate handler2 = _ => Task.FromResult(false); app.OnInit(handler1); app.OnInit(handler2); @@ -513,7 +513,7 @@ public void Build_ImplementsILambdaOnInitBuilder_OnInitMethod() // Arrange var builder = LambdaApplication.CreateBuilder(); var app = builder.Build(); - LambdaInitDelegate handler = (_, _) => Task.FromResult(true); + LambdaInitDelegate handler = _ => Task.FromResult(true); // Act var result = app.OnInit(handler); @@ -529,8 +529,8 @@ public void Build_ImplementsILambdaOnInitBuilder_MultipleHandlers() // Arrange var builder = LambdaApplication.CreateBuilder(); var app = builder.Build(); - LambdaInitDelegate handler1 = (_, _) => Task.FromResult(true); - LambdaInitDelegate handler2 = (_, _) => Task.FromResult(false); + LambdaInitDelegate handler1 = _ => Task.FromResult(true); + LambdaInitDelegate handler2 = _ => Task.FromResult(false); // Act app.OnInit(handler1); diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs index 6a5a5805..9a134ab4 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs @@ -14,6 +14,7 @@ private static IHost CreateHostWithServices() services.ConfigureLambdaHostOptions(_ => { }); services.AddLambdaHostCoreServices(); services.TryAddLambdaHostDefaultServices(); + services.AddSingleton(); }); return builder.Build(); @@ -526,7 +527,7 @@ public void OnInit_WithValidHandler_AddsHandler() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaInitDelegate handler = async (_, _) => true; + LambdaInitDelegate handler = async _ => true; // Act app.OnInit(handler); @@ -541,7 +542,7 @@ public void OnInit_ReturnsBuilder() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaInitDelegate handler = async (_, _) => true; + LambdaInitDelegate handler = async _ => true; // Act var result = app.OnInit(handler); @@ -556,7 +557,7 @@ public void OnInit_EnablesMethodChaining() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaInitDelegate handler = async (_, _) => true; + LambdaInitDelegate handler = async _ => true; // Act var result = app.OnInit(handler).OnInit(handler); @@ -572,7 +573,7 @@ public async Task OnInit_Build_ReturnsCallable() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaInitDelegate handler = async (_, _) => true; + LambdaInitDelegate handler = async _ => true; app.OnInit(handler); // Act @@ -699,7 +700,7 @@ public void AllBuilders_CanBeChainedTogether() var host = CreateHostWithServices(); var app = new LambdaApplication(host); LambdaInvocationDelegate invocationHandler = async _ => await Task.CompletedTask; - LambdaInitDelegate initHandler = async (_, _) => true; + LambdaInitDelegate initHandler = async _ => true; LambdaShutdownDelegate shutdownHandler = async (_, _) => await Task.CompletedTask; // Act diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaOnInitBuilderTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaOnInitBuilderTests.cs index e2204422..e642fccb 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaOnInitBuilderTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaOnInitBuilderTests.cs @@ -8,13 +8,14 @@ public class LambdaOnInitBuilderTests { [Theory] [AutoNSubstituteData] - public void Constructor_WithNullServiceProvider_ThrowsArgumentNullException( + internal void Constructor_WithNullServiceProvider_ThrowsArgumentNullException( IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Act - var act = () => new LambdaOnInitBuilder(null!, scopeFactory, options); + var act = () => new LambdaOnInitBuilder(null!, scopeFactory, options, contextFactory); // Assert act.Should().ThrowExactly().WithParameterName("serviceProvider"); @@ -22,13 +23,14 @@ IOptions options [Theory] [AutoNSubstituteData] - public void Constructor_WithNullScopeFactory_ThrowsArgumentNullException( + internal void Constructor_WithNullScopeFactory_ThrowsArgumentNullException( IServiceProvider serviceProvider, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Act - var act = () => new LambdaOnInitBuilder(serviceProvider, null!, options); + var act = () => new LambdaOnInitBuilder(serviceProvider, null!, options, contextFactory); // Assert act.Should().ThrowExactly().WithParameterName("scopeFactory"); @@ -36,13 +38,15 @@ IOptions options [Theory] [AutoNSubstituteData] - public void Constructor_WithNullOptions_ThrowsArgumentNullException( + internal void Constructor_WithNullOptions_ThrowsArgumentNullException( IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory + IServiceScopeFactory scopeFactory, + ILambdaLifecycleContextFactory contextFactory ) { // Act - var act = () => new LambdaOnInitBuilder(serviceProvider, scopeFactory, null!); + var act = () => + new LambdaOnInitBuilder(serviceProvider, scopeFactory, null!, contextFactory); // Assert act.Should().ThrowExactly().WithParameterName("options"); @@ -50,14 +54,20 @@ IServiceScopeFactory scopeFactory [Theory] [AutoNSubstituteData] - public void Constructor_WithValidParameters_Succeeds( + internal void Constructor_WithValidParameters_Succeeds( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Act - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + options, + contextFactory + ); // Assert builder.Should().NotBeNull(); @@ -66,14 +76,20 @@ IOptions options [Theory] [AutoNSubstituteData] - public void Services_ReturnsServiceProvider( + internal void Services_ReturnsServiceProvider( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Arrange - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + options, + contextFactory + ); // Act var result = builder.Services; @@ -84,14 +100,20 @@ IOptions options [Theory] [AutoNSubstituteData] - public void InitHandlers_ReturnsReadOnlyList( + internal void InitHandlers_ReturnsReadOnlyList( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Arrange - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + options, + contextFactory + ); // Act var handlers = builder.InitHandlers; @@ -104,14 +126,20 @@ IOptions options [Theory] [AutoNSubstituteData] - public void OnInit_WithNullHandler_ThrowsArgumentNullException( + internal void OnInit_WithNullHandler_ThrowsArgumentNullException( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Arrange - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + options, + contextFactory + ); // Act var act = () => builder.OnInit(null!); @@ -122,15 +150,21 @@ IOptions options [Theory] [AutoNSubstituteData] - public void OnInit_WithValidHandler_AddsHandlerAndReturnsBuilder( + internal void OnInit_WithValidHandler_AddsHandlerAndReturnsBuilder( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Arrange - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); - LambdaInitDelegate handler = (_, _) => Task.FromResult(true); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + options, + contextFactory + ); + LambdaInitDelegate handler = _ => Task.FromResult(true); // Act var result = builder.OnInit(handler); @@ -142,17 +176,23 @@ IOptions options [Theory] [AutoNSubstituteData] - public void OnInit_MultipleHandlers_AllAdded( + internal void OnInit_MultipleHandlers_AllAdded( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Arrange - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); - LambdaInitDelegate handler1 = (_, _) => Task.FromResult(true); - LambdaInitDelegate handler2 = (_, _) => Task.FromResult(true); - LambdaInitDelegate handler3 = (_, _) => Task.FromResult(true); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + options, + contextFactory + ); + LambdaInitDelegate handler1 = _ => Task.FromResult(true); + LambdaInitDelegate handler2 = _ => Task.FromResult(true); + LambdaInitDelegate handler3 = _ => Task.FromResult(true); // Act builder.OnInit(handler1); @@ -166,21 +206,26 @@ IOptions options [Theory] [AutoNSubstituteData] - public async Task Build_WithoutHandlers_ReturnsAlwaysTrueFunction( + internal async Task Build_WithoutHandlers_ReturnsNull( IServiceProvider serviceProvider, IServiceScopeFactory scopeFactory, - IOptions options + IOptions options, + ILambdaLifecycleContextFactory contextFactory ) { // Arrange - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, options); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + options, + contextFactory + ); // Act var buildFunc = builder.Build(); - var result = await buildFunc(CancellationToken.None); // Assert - result.Should().BeTrue(); + buildFunc.Should().BeNull(); } [Fact] @@ -192,10 +237,16 @@ public async Task Build_WithSingleSuccessfulHandler_ReturnsTrue() var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions() ); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var contextFactory = Substitute.For(); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); var handlerCalled = false; - LambdaInitDelegate handler = (_, _) => + LambdaInitDelegate handler = _ => { handlerCalled = true; return Task.FromResult(true); @@ -205,6 +256,7 @@ public async Task Build_WithSingleSuccessfulHandler_ReturnsTrue() // Act var buildFunc = builder.Build(); + buildFunc.Should().NotBeNull(); var result = await buildFunc(CancellationToken.None); // Assert @@ -221,9 +273,15 @@ public async Task Build_WithHandlerReturnsFalse_ReturnsFalse() var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions() ); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var contextFactory = Substitute.For(); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); - LambdaInitDelegate handler = (_, _) => Task.FromResult(false); + LambdaInitDelegate handler = _ => Task.FromResult(false); builder.OnInit(handler); @@ -244,24 +302,30 @@ public async Task Build_WithMultipleHandlers_AllExecuted() var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions() ); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var contextFactory = Substitute.For(); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); var handler1Called = false; var handler2Called = false; var handler3Called = false; - LambdaInitDelegate handler1 = (_, _) => + LambdaInitDelegate handler1 = _ => { handler1Called = true; return Task.FromResult(true); }; - LambdaInitDelegate handler2 = (_, _) => + LambdaInitDelegate handler2 = _ => { handler2Called = true; return Task.FromResult(true); }; - LambdaInitDelegate handler3 = (_, _) => + LambdaInitDelegate handler3 = _ => { handler3Called = true; return Task.FromResult(true); @@ -291,11 +355,17 @@ public async Task Build_WithAnyHandlerReturningFalse_ReturnsFalse() var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions() ); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var contextFactory = Substitute.For(); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); - LambdaInitDelegate handler1 = (_, _) => Task.FromResult(true); - LambdaInitDelegate handler2 = (_, _) => Task.FromResult(false); - LambdaInitDelegate handler3 = (_, _) => Task.FromResult(true); + LambdaInitDelegate handler1 = _ => Task.FromResult(true); + LambdaInitDelegate handler2 = _ => Task.FromResult(false); + LambdaInitDelegate handler3 = _ => Task.FromResult(true); builder.OnInit(handler1); builder.OnInit(handler2); @@ -318,10 +388,16 @@ public async Task Build_WhenHandlerThrowsException_ThrowsAggregateException() var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions() ); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var contextFactory = Substitute.For(); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); var testException = new InvalidOperationException("Test error"); - LambdaInitDelegate handler = (_, _) => throw testException; + LambdaInitDelegate handler = _ => throw testException; builder.OnInit(handler); @@ -342,13 +418,19 @@ public async Task Build_WithMultipleFailures_AggregatesAllErrors() var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions() ); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var contextFactory = Substitute.For(); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); var exception1 = new InvalidOperationException("Error 1"); var exception2 = new ArgumentException("Error 2"); - LambdaInitDelegate handler1 = (_, _) => throw exception1; + LambdaInitDelegate handler1 = _ => throw exception1; - LambdaInitDelegate handler2 = (_, _) => throw exception2; + LambdaInitDelegate handler2 = _ => throw exception2; builder.OnInit(handler1); builder.OnInit(handler2); @@ -363,18 +445,26 @@ public async Task Build_WithMultipleFailures_AggregatesAllErrors() [Theory] [AutoNSubstituteData] - public async Task Build_RespectsInitTimeout(IServiceScopeFactory scopeFactory) + internal async Task Build_RespectsInitTimeout( + IServiceScopeFactory scopeFactory, + ILambdaLifecycleContextFactory contextFactory + ) { // Arrange var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions { InitTimeout = TimeSpan.FromMilliseconds(50) } ); var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); - LambdaInitDelegate slowHandler = async (_, cancellationToken) => + LambdaInitDelegate slowHandler = async context => { - await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); + await Task.Delay(TimeSpan.FromSeconds(10), context.CancellationToken); return true; }; @@ -390,22 +480,28 @@ public async Task Build_RespectsInitTimeout(IServiceScopeFactory scopeFactory) [Theory] [AutoNSubstituteData] - public async Task Build_CreatesServiceScopeForEachHandler( + internal async Task Build_CreatesServiceScopeForEachHandler( IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory + IServiceScopeFactory scopeFactory, + ILambdaLifecycleContextFactory contextFactory ) { // Arrange var lambdaHostOptions = Microsoft.Extensions.Options.Options.Create( new LambdaHostOptions() ); - var builder = new LambdaOnInitBuilder(serviceProvider, scopeFactory, lambdaHostOptions); + var builder = new LambdaOnInitBuilder( + serviceProvider, + scopeFactory, + lambdaHostOptions, + contextFactory + ); var scopeUsed = false; - LambdaInitDelegate handler = (scope, _) => + LambdaInitDelegate handler = context => { - scopeUsed = scope != serviceProvider; + scopeUsed = context.ServiceProvider != serviceProvider; return Task.FromResult(true); }; diff --git a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs index 7d387a1b..3f8413c0 100644 --- a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs @@ -14,6 +14,7 @@ private static IHost CreateHostWithServices() services.ConfigureLambdaHostOptions(_ => { }); services.AddLambdaHostCoreServices(); services.TryAddLambdaHostDefaultServices(); + services.AddSingleton(); }); return builder.Build(); From ed6b8c2e5b949c467b47a395abce749e918325a3 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 14:22:44 -0500 Subject: [PATCH 13/27] refactor(unit-tests): simplify `CreateHostWithServices` using `LambdaApplicationBuilder` - Replaced manual host configuration with `LambdaApplicationBuilder` for cleaner test setups. - Updated related test files to utilize `LambdaApplicationBuilder` for creating hosts. --- ...MiddlewareLambdaApplicationExtensionsTests.cs | 16 ++-------------- .../Builder/LambdaApplicationTests.cs | 16 ++-------------- ...FormattingLambdaApplicationExtensionsTests.cs | 16 ++-------------- 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs index 45145823..7bfcec70 100644 --- a/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/Extensions/MiddlewareLambdaApplicationExtensionsTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace MinimalLambda.UnitTests.Application.Extensions; @@ -6,19 +5,8 @@ namespace MinimalLambda.UnitTests.Application.Extensions; [TestSubject(typeof(MiddlewareLambdaApplicationExtensions))] public class MiddlewareLambdaApplicationExtensionsTests { - private static IHost CreateHostWithServices() - { - var builder = Host.CreateDefaultBuilder(); - builder.ConfigureServices(services => - { - services.ConfigureLambdaHostOptions(_ => { }); - services.AddLambdaHostCoreServices(); - services.TryAddLambdaHostDefaultServices(); - services.AddSingleton(); - }); - - return builder.Build(); - } + private static IHost CreateHostWithServices() => + new LambdaApplicationBuilder(new LambdaApplicationOptions()).Build(); [Fact] public void UseMiddleware_WithNullApplication_ThrowsArgumentNullException() diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs index 9a134ab4..6a191323 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace MinimalLambda.UnitTests.Application; @@ -6,19 +5,8 @@ namespace MinimalLambda.UnitTests.Application; [TestSubject(typeof(LambdaApplication))] public class LambdaApplicationTests { - private static IHost CreateHostWithServices() - { - var builder = Host.CreateDefaultBuilder(); - builder.ConfigureServices(services => - { - services.ConfigureLambdaHostOptions(_ => { }); - services.AddLambdaHostCoreServices(); - services.TryAddLambdaHostDefaultServices(); - services.AddSingleton(); - }); - - return builder.Build(); - } + private static IHost CreateHostWithServices() => + new LambdaApplicationBuilder(new LambdaApplicationOptions()).Build(); [Fact] public void Constructor_WithNullHost_ThrowsArgumentNullException() diff --git a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs index 3f8413c0..23639c55 100644 --- a/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/OnInit/OutputFormattingLambdaApplicationExtensionsTests.cs @@ -1,4 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace MinimalLambda.UnitTests.Application.Extensions; @@ -6,19 +5,8 @@ namespace MinimalLambda.UnitTests.Application.Extensions; [TestSubject(typeof(OutputFormattingLambdaApplicationExtensions))] public class OutputFormattingLambdaApplicationExtensionsTests { - private static IHost CreateHostWithServices() - { - var builder = Host.CreateDefaultBuilder(); - builder.ConfigureServices(services => - { - services.ConfigureLambdaHostOptions(_ => { }); - services.AddLambdaHostCoreServices(); - services.TryAddLambdaHostDefaultServices(); - services.AddSingleton(); - }); - - return builder.Build(); - } + private static IHost CreateHostWithServices() => + new LambdaApplicationBuilder(new LambdaApplicationOptions()).Build(); [Fact] public void OnInitClearLambdaOutputFormatting_WithNullApplication_ThrowsArgumentNullException() From e842f971d99c112f4fe0e2befef15f3ddec0d085 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 18:44:04 -0500 Subject: [PATCH 14/27] feat(minimal-lambda): enhance shutdown handling with `ILambdaLifecycleContext` and shared state - Updated `LambdaShutdownDelegate` to use `ILambdaLifecycleContext`, replacing `IServiceProvider` and `CancellationToken`. - Added `Properties` dictionary to `ILambdaOnShutdownBuilder` for shared state between handlers. - Unified `Properties` documentation between `ILambdaOnInitBuilder` and `ILambdaOnShutdownBuilder`. --- .../Builders/ILambdaOnInitBuilder.cs | 2 +- .../Builders/ILambdaOnShutdownBuilder.cs | 5 +++++ .../Delegates/LambdaShutdownDelegate.cs | 12 ++++-------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs b/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs index 2bc508b6..4343d8fb 100644 --- a/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs +++ b/src/MinimalLambda.Abstractions/Builders/ILambdaOnInitBuilder.cs @@ -20,7 +20,7 @@ public interface ILambdaOnInitBuilder /// Gets the read-only list of registered Init handlers. IReadOnlyList InitHandlers { get; } - /// Gets a dictionary for storing state that is shared across Init handlers. + /// Gets a dictionary for storing state that is shared between handlers. ConcurrentDictionary Properties { get; } /// Gets the service provider for dependency injection. diff --git a/src/MinimalLambda.Abstractions/Builders/ILambdaOnShutdownBuilder.cs b/src/MinimalLambda.Abstractions/Builders/ILambdaOnShutdownBuilder.cs index 736c6b53..2a3dc4c9 100644 --- a/src/MinimalLambda.Abstractions/Builders/ILambdaOnShutdownBuilder.cs +++ b/src/MinimalLambda.Abstractions/Builders/ILambdaOnShutdownBuilder.cs @@ -1,3 +1,5 @@ +using System.Collections.Concurrent; + namespace MinimalLambda.Builder; /// Builder for composing Lambda shutdown handlers that execute during the Shutdown phase. @@ -17,6 +19,9 @@ public interface ILambdaOnShutdownBuilder /// Gets the service provider for dependency injection. IServiceProvider Services { get; } + /// Gets a dictionary for storing state that is shared between handlers. + ConcurrentDictionary Properties { get; } + /// Gets the read-only list of registered shutdown handlers. IReadOnlyList ShutdownHandlers { get; } diff --git a/src/MinimalLambda.Abstractions/Delegates/LambdaShutdownDelegate.cs b/src/MinimalLambda.Abstractions/Delegates/LambdaShutdownDelegate.cs index 881215aa..65b64a32 100644 --- a/src/MinimalLambda.Abstractions/Delegates/LambdaShutdownDelegate.cs +++ b/src/MinimalLambda.Abstractions/Delegates/LambdaShutdownDelegate.cs @@ -1,14 +1,10 @@ namespace MinimalLambda; /// A callback delegate invoked during the AWS Lambda Function Shutdown phase. -/// A scoped for resolving dependencies. -/// -/// Signals the handler to stop. Expires before the Lambda runtime's -/// hard timeout. +/// +/// The providing access to the scoped +/// and for the Function Shutdown phase. /// /// A representing the shutdown operation. /// -public delegate Task LambdaShutdownDelegate( - IServiceProvider services, - CancellationToken cancellationToken -); +public delegate Task LambdaShutdownDelegate(ILambdaLifecycleContext context); From adf0abc2b26930e4f05112624797e5abc2e58b56 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 18:45:49 -0500 Subject: [PATCH 15/27] feat(minimal-lambda): update `OnInit` and `OnShutdown` for improved logging and handler simplicity - Replaced `Console.WriteLine` with `ILogger` for better logging flexibility in `OnInit`. - Simplified `OnInit` handler signature, removing `IServiceCollection` from unused parameters. - Refactored `OnShutdown` to streamline the handler and remove unnecessary parameters. --- .../Program.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/MinimalLambda.Example.Lifecycle/Program.cs b/examples/MinimalLambda.Example.Lifecycle/Program.cs index 3692dabc..139497cf 100644 --- a/examples/MinimalLambda.Example.Lifecycle/Program.cs +++ b/examples/MinimalLambda.Example.Lifecycle/Program.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; using MinimalLambda.Builder; var builder = LambdaApplication.CreateBuilder(); @@ -20,22 +21,21 @@ lambda.UseClearLambdaOutputFormatting(); -lambda.OnInit( - Task (IServiceCollection services, CancellationToken cancellationToken) => - { - Console.WriteLine("Initializing..."); - return Task.FromResult(true); - } -); +lambda.OnInit(() => +{ + Console.WriteLine("Initializing..."); + return Task.FromResult(true); +}); lambda.OnInit( - async Task (IServiceCollection services, CancellationToken cancellationToken) => + async Task (ILogger logger, CancellationToken cancellationToken) => { var stopwatch = Stopwatch.StartNew(); while (!cancellationToken.IsCancellationRequested) { - Console.WriteLine( - $"Waiting for init to timeout. {stopwatch.ElapsedMilliseconds}ms elapsed" + logger.LogInformation( + "Waiting for init to timeout. {ElapsedMilliseconds}ms elapsed", + stopwatch.ElapsedMilliseconds ); try { @@ -58,7 +58,7 @@ async Task (IServiceCollection services, CancellationToken cancellationTok }); lambda.OnShutdown( - (IServiceCollection services, CancellationToken token) => + (CancellationToken token) => { Console.WriteLine("Shutting down..."); return Task.CompletedTask; From 6b19eb668ab38c0a7f66c9d674e4b8be8a85986e Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 18:49:36 -0500 Subject: [PATCH 16/27] feat(minimal-lambda): enhance `OnShutdown` with context factory and shared properties support - Added `ILambdaLifecycleContextFactory` to `LambdaOnShutdownBuilder` for creating lifecycle contexts. - Integrated `Properties` dictionary to enable shared state management between shutdown handlers. - Updated `LambdaShutdownDelegate` to use lifecycle context for improved consistency with `OnInit`. - Modified `DefaultLambdaOnShutdownBuilderFactory` to support context factory injection. --- .../DefaultLambdaOnShutdownBuilderFactory.cs | 5 +++-- .../Builder/LambdaApplication.cs | 4 ++++ .../Builder/LambdaOnShutdownBuilder.cs | 21 +++++++++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/MinimalLambda/Builder/DefaultLambdaOnShutdownBuilderFactory.cs b/src/MinimalLambda/Builder/DefaultLambdaOnShutdownBuilderFactory.cs index a9038709..cf001441 100644 --- a/src/MinimalLambda/Builder/DefaultLambdaOnShutdownBuilderFactory.cs +++ b/src/MinimalLambda/Builder/DefaultLambdaOnShutdownBuilderFactory.cs @@ -4,9 +4,10 @@ namespace MinimalLambda.Builder; internal class DefaultLambdaOnShutdownBuilderFactory( IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory + IServiceScopeFactory scopeFactory, + ILambdaLifecycleContextFactory contextFactory ) : ILambdaOnShutdownBuilderFactory { public ILambdaOnShutdownBuilder CreateBuilder() => - new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); + new LambdaOnShutdownBuilder(serviceProvider, scopeFactory, contextFactory); } diff --git a/src/MinimalLambda/Builder/LambdaApplication.cs b/src/MinimalLambda/Builder/LambdaApplication.cs index d36a988f..497f7af3 100644 --- a/src/MinimalLambda/Builder/LambdaApplication.cs +++ b/src/MinimalLambda/Builder/LambdaApplication.cs @@ -136,6 +136,10 @@ public ILambdaOnInitBuilder OnInit(LambdaInitDelegate handler) public IReadOnlyList ShutdownHandlers => _onShutdownBuilder.ShutdownHandlers; + /// + ConcurrentDictionary ILambdaOnShutdownBuilder.Properties => + _onInitBuilder.Properties; + /// public ILambdaOnShutdownBuilder OnShutdown(LambdaShutdownDelegate handler) { diff --git a/src/MinimalLambda/Builder/LambdaOnShutdownBuilder.cs b/src/MinimalLambda/Builder/LambdaOnShutdownBuilder.cs index be9080f4..2b11a0bd 100644 --- a/src/MinimalLambda/Builder/LambdaOnShutdownBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaOnShutdownBuilder.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using Microsoft.Extensions.DependencyInjection; namespace MinimalLambda.Builder; @@ -6,20 +7,27 @@ internal class LambdaOnShutdownBuilder : ILambdaOnShutdownBuilder { private readonly IList _handlers = []; private readonly IServiceScopeFactory _scopeFactory; + private readonly ILambdaLifecycleContextFactory _contextFactory; public LambdaOnShutdownBuilder( IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory + IServiceScopeFactory scopeFactory, + ILambdaLifecycleContextFactory contextFactory ) { ArgumentNullException.ThrowIfNull(serviceProvider); ArgumentNullException.ThrowIfNull(scopeFactory); + ArgumentNullException.ThrowIfNull(contextFactory); Services = serviceProvider; _scopeFactory = scopeFactory; + _contextFactory = contextFactory; } public IServiceProvider Services { get; } + + public ConcurrentDictionary Properties { get; } = new(); + public IReadOnlyList ShutdownHandlers => _handlers.AsReadOnly(); public ILambdaOnShutdownBuilder OnShutdown(LambdaShutdownDelegate handler) @@ -55,9 +63,14 @@ CancellationToken cancellationToken { try { - using var scope = _scopeFactory.CreateScope(); - await handler(scope.ServiceProvider, cancellationToken).ConfigureAwait(false); - return null; + var context = _contextFactory.Create(Properties, cancellationToken); + + await using (context as IAsyncDisposable) + { + using var scope = _scopeFactory.CreateScope(); + await handler(context).ConfigureAwait(false); + return null; + } } catch (Exception ex) { From 657f88b2d1fbaed5fff67a4de59346c3fd8acd4e Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:07:04 -0500 Subject: [PATCH 17/27] feat(opentelemetry): update shutdown handlers and add project references - Refactored `OnShutdown` handlers to simplify parameter usage by removing unused lambda arguments. - Added `MinimalLambda.SourceGenerators` as an analyzer and updated project references for extended functionality. --- .../MinimalLambda.OpenTelemetry.csproj | 7 +++++++ .../OnShutdownOpenTelemetryExtensions.cs | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj b/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj index a34277e2..24c2b1ea 100644 --- a/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj +++ b/src/MinimalLambda.OpenTelemetry/MinimalLambda.OpenTelemetry.csproj @@ -11,9 +11,16 @@ MinimalLambda.OpenTelemetry OpenTelemetry integration for MinimalLambda README.md + $(InterceptorsNamespaces);MinimalLambda.Generated + + diff --git a/src/MinimalLambda.OpenTelemetry/OnShutdownOpenTelemetryExtensions.cs b/src/MinimalLambda.OpenTelemetry/OnShutdownOpenTelemetryExtensions.cs index 3ce38533..f97d8fd2 100644 --- a/src/MinimalLambda.OpenTelemetry/OnShutdownOpenTelemetryExtensions.cs +++ b/src/MinimalLambda.OpenTelemetry/OnShutdownOpenTelemetryExtensions.cs @@ -79,7 +79,7 @@ public ILambdaOnShutdownBuilder OnShutdownFlushTracer( ?? NullLogger.Instance; application.OnShutdown( - (_, cancellationToken) => + (CancellationToken cancellationToken) => RunForceFlush( "tracer", tracerProvider.ForceFlush, @@ -123,7 +123,7 @@ public ILambdaOnShutdownBuilder OnShutdownFlushMeter( ?? NullLogger.Instance; application.OnShutdown( - (_, cancellationToken) => + (CancellationToken cancellationToken) => RunForceFlush( "meter", meterProvider.ForceFlush, From 3ddfefb1da06b8b4e14648056936280f1a17f3b4 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:07:14 -0500 Subject: [PATCH 18/27] feat(source-generators): update `OnShutdown` syntax provider to use `ILambdaLifecycleContext` - Replaced `IServiceProvider` and `CancellationToken` with `ILambdaLifecycleContext` in `OnShutdown`. - Streamlined syntax matching for improved consistency and maintainability. --- .../SyntaxProviders/OnShutdownSyntaxProvider.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnShutdownSyntaxProvider.cs b/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnShutdownSyntaxProvider.cs index b96bf94b..142643ea 100644 --- a/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnShutdownSyntaxProvider.cs +++ b/src/MinimalLambda.SourceGenerators/SyntaxProviders/OnShutdownSyntaxProvider.cs @@ -22,8 +22,7 @@ private static bool IsBaseOnShutdownCall(this DelegateInfo delegateInfo) => is { ReturnTypeInfo.FullyQualifiedType: TypeConstants.Task, Parameters: [ - { TypeInfo.FullyQualifiedType: TypeConstants.IServiceProvider }, - { TypeInfo.FullyQualifiedType: TypeConstants.CancellationToken }, + { TypeInfo.FullyQualifiedType: TypeConstants.ILambdaLifecycleContext }, ], }; } From 72aa4cf42b69bc87f2cfde5b43456bb782f2af85 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:07:32 -0500 Subject: [PATCH 19/27] refactor(unit-tests): streamline `LambdaOnShutdownBuilder` test methods - Simplified test setups by removing redundant `IServiceProvider` and `IServiceScopeFactory` parameters. - Updated `LambdaShutdownDelegate` usage to align with recent changes, replacing unused lambda arguments. - Converted constructors and Fact-based test methods to enhanced Theory-based design for improved flexibility. --- .../Builder/LambdaOnShutdownBuilderTests.cs | 250 ++++-------------- 1 file changed, 45 insertions(+), 205 deletions(-) diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaOnShutdownBuilderTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaOnShutdownBuilderTests.cs index e3483509..1429402c 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaOnShutdownBuilderTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaOnShutdownBuilderTests.cs @@ -1,5 +1,3 @@ -using Microsoft.Extensions.DependencyInjection; - namespace MinimalLambda.UnitTests.Builder; [TestSubject(typeof(LambdaOnShutdownBuilder))] @@ -7,72 +5,8 @@ public class LambdaOnShutdownBuilderTests { [Theory] [AutoNSubstituteData] - public void Constructor_WithNullServiceProvider_ThrowsArgumentNullException( - IServiceScopeFactory scopeFactory - ) - { - // Act - var act = () => new LambdaOnShutdownBuilder(null!, scopeFactory); - - // Assert - act.Should().ThrowExactly().WithParameterName("serviceProvider"); - } - - [Theory] - [AutoNSubstituteData] - public void Constructor_WithNullScopeFactory_ThrowsArgumentNullException( - IServiceProvider serviceProvider - ) - { - // Act - var act = () => new LambdaOnShutdownBuilder(serviceProvider, null!); - - // Assert - act.Should().ThrowExactly().WithParameterName("scopeFactory"); - } - - [Theory] - [AutoNSubstituteData] - public void Constructor_WithValidParameters_Succeeds( - IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory - ) + internal void ShutdownHandlers_ReturnsReadOnlyList(LambdaOnShutdownBuilder builder) { - // Act - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - - // Assert - builder.Should().NotBeNull(); - builder.Services.Should().Be(serviceProvider); - } - - [Theory] - [AutoNSubstituteData] - public void Services_ReturnsServiceProvider( - IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory - ) - { - // Arrange - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - - // Act - var result = builder.Services; - - // Assert - result.Should().Be(serviceProvider); - } - - [Theory] - [AutoNSubstituteData] - public void ShutdownHandlers_ReturnsReadOnlyList( - IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory - ) - { - // Arrange - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - // Act var handlers = builder.ShutdownHandlers; @@ -84,14 +18,10 @@ IServiceScopeFactory scopeFactory [Theory] [AutoNSubstituteData] - public void OnShutdown_WithNullHandler_ThrowsArgumentNullException( - IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory + internal void OnShutdown_WithNullHandler_ThrowsArgumentNullException( + LambdaOnShutdownBuilder builder ) { - // Arrange - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - // Act var act = () => builder.OnShutdown(null!); @@ -101,14 +31,12 @@ IServiceScopeFactory scopeFactory [Theory] [AutoNSubstituteData] - public void OnShutdown_WithValidHandler_AddsHandlerAndReturnsBuilder( - IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory + internal void OnShutdown_WithValidHandler_AddsHandlerAndReturnsBuilder( + LambdaOnShutdownBuilder builder ) { // Arrange - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - LambdaShutdownDelegate handler = (_, _) => Task.CompletedTask; + LambdaShutdownDelegate handler = _ => Task.CompletedTask; // Act var result = builder.OnShutdown(handler); @@ -120,16 +48,12 @@ IServiceScopeFactory scopeFactory [Theory] [AutoNSubstituteData] - public void OnShutdown_MultipleHandlers_AllAdded( - IServiceProvider serviceProvider, - IServiceScopeFactory scopeFactory - ) + internal void OnShutdown_MultipleHandlers_AllAdded(LambdaOnShutdownBuilder builder) { // Arrange - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - LambdaShutdownDelegate handler1 = (_, _) => Task.CompletedTask; - LambdaShutdownDelegate handler2 = (_, _) => Task.CompletedTask; - LambdaShutdownDelegate handler3 = (_, _) => Task.CompletedTask; + LambdaShutdownDelegate handler1 = _ => Task.CompletedTask; + LambdaShutdownDelegate handler2 = _ => Task.CompletedTask; + LambdaShutdownDelegate handler3 = _ => Task.CompletedTask; // Act builder.OnShutdown(handler1); @@ -141,14 +65,12 @@ IServiceScopeFactory scopeFactory builder.ShutdownHandlers.Should().Equal(handler1, handler2, handler3); } - [Fact] - public async Task Build_WithoutHandlers_ReturnsCompletedTaskFunction() + [Theory] + [AutoNSubstituteData] + internal async Task Build_WithoutHandlers_ReturnsCompletedTaskFunction( + LambdaOnShutdownBuilder builder + ) { - // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - // Act var buildFunc = builder.Build(); var task = buildFunc(CancellationToken.None); @@ -158,16 +80,14 @@ public async Task Build_WithoutHandlers_ReturnsCompletedTaskFunction() task.IsCompletedSuccessfully.Should().BeTrue(); } - [Fact] - public async Task Build_WithSingleHandler_ExecutesHandler() + [Theory] + [AutoNSubstituteData] + internal async Task Build_WithSingleHandler_ExecutesHandler(LambdaOnShutdownBuilder builder) { // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); var handlerCalled = false; - LambdaShutdownDelegate handler = (_, _) => + LambdaShutdownDelegate handler = _ => { handlerCalled = true; return Task.CompletedTask; @@ -183,30 +103,28 @@ public async Task Build_WithSingleHandler_ExecutesHandler() handlerCalled.Should().BeTrue(); } - [Fact] - public async Task Build_WithMultipleHandlers_AllExecuted() + [Theory] + [AutoNSubstituteData] + internal async Task Build_WithMultipleHandlers_AllExecuted(LambdaOnShutdownBuilder builder) { // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); var handler1Called = false; var handler2Called = false; var handler3Called = false; - LambdaShutdownDelegate handler1 = (_, _) => + LambdaShutdownDelegate handler1 = _ => { handler1Called = true; return Task.CompletedTask; }; - LambdaShutdownDelegate handler2 = (_, _) => + LambdaShutdownDelegate handler2 = _ => { handler2Called = true; return Task.CompletedTask; }; - LambdaShutdownDelegate handler3 = (_, _) => + LambdaShutdownDelegate handler3 = _ => { handler3Called = true; return Task.CompletedTask; @@ -226,16 +144,16 @@ public async Task Build_WithMultipleHandlers_AllExecuted() handler3Called.Should().BeTrue(); } - [Fact] - public async Task Build_WhenHandlerThrowsException_ThrowsAggregateException() + [Theory] + [AutoNSubstituteData] + internal async Task Build_WhenHandlerThrowsException_ThrowsAggregateException( + LambdaOnShutdownBuilder builder + ) { // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); var testException = new InvalidOperationException("Test error"); - LambdaShutdownDelegate handler = (_, _) => throw testException; + LambdaShutdownDelegate handler = _ => throw testException; builder.OnShutdown(handler); @@ -247,19 +165,19 @@ public async Task Build_WhenHandlerThrowsException_ThrowsAggregateException() await act.Should().ThrowAsync(); } - [Fact] - public async Task Build_WithMultipleFailures_AggregatesAllErrors() + [Theory] + [AutoNSubstituteData] + internal async Task Build_WithMultipleFailures_AggregatesAllErrors( + LambdaOnShutdownBuilder builder + ) { // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); var exception1 = new InvalidOperationException("Error 1"); var exception2 = new ArgumentException("Error 2"); - LambdaShutdownDelegate handler1 = (_, _) => throw exception1; + LambdaShutdownDelegate handler1 = _ => throw exception1; - LambdaShutdownDelegate handler2 = (_, _) => throw exception2; + LambdaShutdownDelegate handler2 = _ => throw exception2; builder.OnShutdown(handler1); builder.OnShutdown(handler2); @@ -272,23 +190,23 @@ public async Task Build_WithMultipleFailures_AggregatesAllErrors() await act.Should().ThrowAsync(); } - [Fact] - public async Task Build_WithMixedSuccessAndFailure_AggregatesOnlyErrors() + [Theory] + [AutoNSubstituteData] + internal async Task Build_WithMixedSuccessAndFailure_AggregatesOnlyErrors( + LambdaOnShutdownBuilder builder + ) { // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); var successfulHandlerCalled = false; var testException = new InvalidOperationException("Test error"); - LambdaShutdownDelegate successHandler = (_, _) => + LambdaShutdownDelegate successHandler = _ => { successfulHandlerCalled = true; return Task.CompletedTask; }; - LambdaShutdownDelegate failingHandler = (_, _) => throw testException; + LambdaShutdownDelegate failingHandler = _ => throw testException; builder.OnShutdown(successHandler); builder.OnShutdown(failingHandler); @@ -301,82 +219,4 @@ public async Task Build_WithMixedSuccessAndFailure_AggregatesOnlyErrors() await act.Should().ThrowAsync(); successfulHandlerCalled.Should().BeTrue(); } - - [Fact] - public async Task Build_CreatesServiceScopeForEachHandler() - { - // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - - var scopeUsed = false; - - LambdaShutdownDelegate handler = (scope, _) => - { - scopeUsed = scope != serviceProvider; - return Task.CompletedTask; - }; - - builder.OnShutdown(handler); - - // Act - var buildFunc = builder.Build(); - await buildFunc(CancellationToken.None); - - // Assert - scopeUsed.Should().BeTrue(); - } - - [Fact] - public async Task Build_RespectsCancellationToken() - { - // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - - var cancellationTokenReceived = false; - - LambdaShutdownDelegate handler = (_, cancellationToken) => - { - cancellationTokenReceived = !cancellationToken.IsCancellationRequested; - return Task.CompletedTask; - }; - - builder.OnShutdown(handler); - - // Act - var buildFunc = builder.Build(); - using var cts = new CancellationTokenSource(); - await buildFunc(cts.Token); - - // Assert - cancellationTokenReceived.Should().BeTrue(); - } - - [Fact] - public async Task Build_WithCancelledToken_RespectsCancellation() - { - // Arrange - var serviceProvider = new ServiceCollection().BuildServiceProvider(); - var scopeFactory = serviceProvider.GetRequiredService(); - var builder = new LambdaOnShutdownBuilder(serviceProvider, scopeFactory); - - LambdaShutdownDelegate handler = async (_, cancellationToken) => - { - await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); - }; - - builder.OnShutdown(handler); - - // Act - var buildFunc = builder.Build(); - using var cts = new CancellationTokenSource(); - cts.Cancel(); - var act = () => buildFunc(cts.Token); - - // Assert - await act.Should().ThrowAsync(); - } } From 5e14df5cf59bf31263c74bfa7740ef9dfed5f278 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:10:01 -0500 Subject: [PATCH 20/27] test(unit-tests): add `ILambdaLifecycleContextFactory` to shutdown factory tests - Updated `DefaultLambdaOnShutdownBuilderFactoryTests` to include `ILambdaLifecycleContextFactory`. - Added validation for null `ILambdaLifecycleContextFactory` in test cases. - Refactored test setups to accommodate the new context factory parameter in the factory constructor. --- ...aultLambdaOnShutdownBuilderFactoryTests.cs | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnShutdownBuilderFactoryTests.cs b/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnShutdownBuilderFactoryTests.cs index 0f3d6db5..f3a53837 100644 --- a/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnShutdownBuilderFactoryTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/DefaultLambdaOnShutdownBuilderFactoryTests.cs @@ -8,16 +8,25 @@ public class DefaultLambdaOnShutdownBuilderFactoryTests private readonly IServiceScopeFactory _scopeFactory = Substitute.For(); private readonly IServiceProvider _serviceProvider = Substitute.For(); + private readonly ILambdaLifecycleContextFactory _contextFactory = + Substitute.For(); + [Theory] [InlineData(0)] // ServiceProvider [InlineData(1)] // ScopeFactory + [InlineData(2)] // ContextFactory public void CreateBuilder_WithNullParameter_ThrowsArgumentNullException(int parameterIndex) { // Arrange var serviceProvider = parameterIndex == 0 ? null : _serviceProvider; var scopeFactory = parameterIndex == 1 ? null : _scopeFactory; + var contextFactory = parameterIndex == 2 ? null : _contextFactory; - var factory = new DefaultLambdaOnShutdownBuilderFactory(serviceProvider!, scopeFactory!); + var factory = new DefaultLambdaOnShutdownBuilderFactory( + serviceProvider!, + scopeFactory!, + contextFactory! + ); // Act & Assert - validation happens in LambdaOnShutdownBuilder constructor var act = () => factory.CreateBuilder(); @@ -28,7 +37,11 @@ public void CreateBuilder_WithNullParameter_ThrowsArgumentNullException(int para public void Constructor_WithValidParameters_SuccessfullyConstructs() { // Act - var factory = new DefaultLambdaOnShutdownBuilderFactory(_serviceProvider, _scopeFactory); + var factory = new DefaultLambdaOnShutdownBuilderFactory( + _serviceProvider, + _scopeFactory, + _contextFactory + ); // Assert factory.Should().NotBeNull(); @@ -38,7 +51,11 @@ public void Constructor_WithValidParameters_SuccessfullyConstructs() public void CreateBuilder_ReturnsLambdaOnShutdownBuilder() { // Arrange - var factory = new DefaultLambdaOnShutdownBuilderFactory(_serviceProvider, _scopeFactory); + var factory = new DefaultLambdaOnShutdownBuilderFactory( + _serviceProvider, + _scopeFactory, + _contextFactory + ); // Act var builder = factory.CreateBuilder(); @@ -52,7 +69,11 @@ public void CreateBuilder_ReturnsLambdaOnShutdownBuilder() public void CreateBuilder_PassesServiceProviderToBuilder() { // Arrange - var factory = new DefaultLambdaOnShutdownBuilderFactory(_serviceProvider, _scopeFactory); + var factory = new DefaultLambdaOnShutdownBuilderFactory( + _serviceProvider, + _scopeFactory, + _contextFactory + ); // Act var builder = factory.CreateBuilder(); @@ -65,7 +86,11 @@ public void CreateBuilder_PassesServiceProviderToBuilder() public void CreateBuilder_CreatesNewInstanceEachCall() { // Arrange - var factory = new DefaultLambdaOnShutdownBuilderFactory(_serviceProvider, _scopeFactory); + var factory = new DefaultLambdaOnShutdownBuilderFactory( + _serviceProvider, + _scopeFactory, + _contextFactory + ); // Act var builder1 = factory.CreateBuilder(); From 3a4f070a9edd4e38595813b3bea500f9818a1b98 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:11:16 -0500 Subject: [PATCH 21/27] refactor(unit-tests): simplify `LambdaShutdownDelegate` usage in shutdown tests - Removed unused lambda arguments in `LambdaShutdownDelegate` across test cases. - Updated test cases for improved readability and reduced redundancy in lambda signatures. --- .../Builder/LambdaApplicationBuilderTests.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs index dc3b5c76..ae08d734 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationBuilderTests.cs @@ -387,8 +387,8 @@ public void Build_ConfigureOnShutdownBuilderCallback_AppliesShutdownHandlers() var app = builder.Build(); // Register shutdown handlers on the app - LambdaShutdownDelegate handler1 = (_, _) => Task.CompletedTask; - LambdaShutdownDelegate handler2 = (_, _) => Task.CompletedTask; + LambdaShutdownDelegate handler1 = _ => Task.CompletedTask; + LambdaShutdownDelegate handler2 = _ => Task.CompletedTask; app.OnShutdown(handler1); app.OnShutdown(handler2); @@ -436,9 +436,9 @@ public void Build_ConfigureOnShutdownBuilderCallback_WithMultipleHandlers() var app = builder.Build(); // Register multiple shutdown handlers - LambdaShutdownDelegate handler1 = (_, _) => Task.CompletedTask; - LambdaShutdownDelegate handler2 = (_, _) => Task.CompletedTask; - LambdaShutdownDelegate handler3 = (_, _) => Task.CompletedTask; + LambdaShutdownDelegate handler1 = _ => Task.CompletedTask; + LambdaShutdownDelegate handler2 = _ => Task.CompletedTask; + LambdaShutdownDelegate handler3 = _ => Task.CompletedTask; app.OnShutdown(handler1); app.OnShutdown(handler2); app.OnShutdown(handler3); @@ -548,7 +548,7 @@ public void Build_ImplementsILambdaOnShutdownBuilder_OnShutdownMethod() // Arrange var builder = LambdaApplication.CreateBuilder(); var app = builder.Build(); - LambdaShutdownDelegate handler = (_, _) => Task.CompletedTask; + LambdaShutdownDelegate handler = _ => Task.CompletedTask; // Act var result = app.OnShutdown(handler); @@ -564,8 +564,8 @@ public void Build_ImplementsILambdaOnShutdownBuilder_MultipleHandlers() // Arrange var builder = LambdaApplication.CreateBuilder(); var app = builder.Build(); - LambdaShutdownDelegate handler1 = (_, _) => Task.CompletedTask; - LambdaShutdownDelegate handler2 = (_, _) => Task.CompletedTask; + LambdaShutdownDelegate handler1 = _ => Task.CompletedTask; + LambdaShutdownDelegate handler2 = _ => Task.CompletedTask; // Act app.OnShutdown(handler1); From cc75ba19ed3c3510f769a7a6dcb669c6dbb1eb8f Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:12:29 -0500 Subject: [PATCH 22/27] refactor(unit-tests): remove unused parameters from `LambdaShutdownDelegate` in tests - Simplified `LambdaShutdownDelegate` usage by removing unused lambda arguments across test cases. - Updated test cases to improve readability and align with streamlined delegate signatures. --- .../Builder/LambdaApplicationTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs index 6a191323..9e32ad3a 100644 --- a/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs +++ b/tests/MinimalLambda.UnitTests/Builder/LambdaApplicationTests.cs @@ -623,7 +623,7 @@ public void OnShutdown_WithValidHandler_AddsHandler() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaShutdownDelegate handler = async (_, _) => await Task.CompletedTask; + LambdaShutdownDelegate handler = async _ => await Task.CompletedTask; // Act app.OnShutdown(handler); @@ -638,7 +638,7 @@ public void OnShutdown_ReturnsBuilder() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaShutdownDelegate handler = async (_, _) => await Task.CompletedTask; + LambdaShutdownDelegate handler = async _ => await Task.CompletedTask; // Act var result = app.OnShutdown(handler); @@ -653,7 +653,7 @@ public void OnShutdown_EnablesMethodChaining() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaShutdownDelegate handler = async (_, _) => await Task.CompletedTask; + LambdaShutdownDelegate handler = async _ => await Task.CompletedTask; // Act var result = app.OnShutdown(handler).OnShutdown(handler); @@ -669,7 +669,7 @@ public async Task OnShutdown_Build_ReturnsCallable() // Arrange var host = CreateHostWithServices(); var app = new LambdaApplication(host); - LambdaShutdownDelegate handler = async (_, _) => await Task.CompletedTask; + LambdaShutdownDelegate handler = async _ => await Task.CompletedTask; app.OnShutdown(handler); // Act @@ -689,7 +689,7 @@ public void AllBuilders_CanBeChainedTogether() var app = new LambdaApplication(host); LambdaInvocationDelegate invocationHandler = async _ => await Task.CompletedTask; LambdaInitDelegate initHandler = async _ => true; - LambdaShutdownDelegate shutdownHandler = async (_, _) => await Task.CompletedTask; + LambdaShutdownDelegate shutdownHandler = async _ => await Task.CompletedTask; // Act app.Handle(invocationHandler); From 5a101cdcca7627d2d96343d3ed9913397376298b Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:18:56 -0500 Subject: [PATCH 23/27] refactor(unit-tests): replace `IServiceProvider` with `ILambdaLifecycleContext` in tests - Updated shutdown handler tests to use `ILambdaLifecycleContext` instead of `IServiceProvider`. - Refactored mocked contexts and removed direct `CancellationToken` assignments from test cases. - Improved consistency with recent changes to `LambdaShutdownDelegate`. --- .../OnShutdownOpenTelemetryExtensionsTests.cs | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/tests/MinimalLambda.OpenTelemetry.UnitTests/OnShutdownOpenTelemetryExtensionsTests.cs b/tests/MinimalLambda.OpenTelemetry.UnitTests/OnShutdownOpenTelemetryExtensionsTests.cs index 4640433a..b5b66bb1 100644 --- a/tests/MinimalLambda.OpenTelemetry.UnitTests/OnShutdownOpenTelemetryExtensionsTests.cs +++ b/tests/MinimalLambda.OpenTelemetry.UnitTests/OnShutdownOpenTelemetryExtensionsTests.cs @@ -71,13 +71,13 @@ public async Task OnShutdownFlushTracer_RegistersShutdownHandler_AndSuccessfully LambdaShutdownDelegate? capturedShutdownAction = null; var mockApp = CreateMockApp(a => capturedShutdownAction = a); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); // Act var result = mockApp.OnShutdownFlushTracer(); capturedShutdownAction.Should().NotBeNull(); - await capturedShutdownAction.Invoke(mockServiceProvider, CancellationToken.None); + await capturedShutdownAction.Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -106,13 +106,13 @@ public async Task OnShutdownFlushTracer_RegistersShutdownHandler_AndFailedFlushe options => options.TracerShouldSucceed = false ); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); // Act var result = mockApp.OnShutdownFlushTracer(); capturedShutdownAction.Should().NotBeNull(); - await capturedShutdownAction.Invoke(mockServiceProvider, CancellationToken.None); + await capturedShutdownAction.Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -141,13 +141,14 @@ public async Task OnShutdownFlushTracer_RegistersShutdownHandler_AndCanceledFlus options => options.TracerDelay = TimeSpan.FromMilliseconds(10) ); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); + mockContext.CancellationToken.Returns(new CancellationToken(true)); // Act var result = mockApp.OnShutdownFlushTracer(); capturedShutdownAction.Should().NotBeNull(); - await capturedShutdownAction.Invoke(mockServiceProvider, new CancellationToken(true)); + await capturedShutdownAction.Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -229,13 +230,13 @@ public async Task OnShutdownFlushMeter_RegistersShutdownHandler_AndSuccessfullyF LambdaShutdownDelegate? capturedShutdownAction = null; var mockApp = CreateMockApp(a => capturedShutdownAction = a); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); // Act var result = mockApp.OnShutdownFlushMeter(); capturedShutdownAction.Should().NotBeNull(); - await capturedShutdownAction.Invoke(mockServiceProvider, CancellationToken.None); + await capturedShutdownAction.Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -264,13 +265,12 @@ public async Task OnShutdownFlushMeter_RegistersShutdownHandler_AndFailedFlushes options => options.MeterShouldSucceed = false ); - var mockServiceProvider = Substitute.For(); - + var mockContext = Substitute.For(); // Act var result = mockApp.OnShutdownFlushMeter(); capturedShutdownAction.Should().NotBeNull(); - await capturedShutdownAction.Invoke(mockServiceProvider, CancellationToken.None); + await capturedShutdownAction.Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -299,13 +299,14 @@ public async Task OnShutdownFlushMeter_RegistersShutdownHandler_AndCanceledFlush options => options.MeterDelay = TimeSpan.FromMilliseconds(10) ); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); + mockContext.CancellationToken.Returns(new CancellationToken(true)); // Act var result = mockApp.OnShutdownFlushMeter(); capturedShutdownAction.Should().NotBeNull(); - await capturedShutdownAction.Invoke(mockServiceProvider, new CancellationToken(true)); + await capturedShutdownAction.Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -389,14 +390,14 @@ public async Task OnShutdownFlushOpenTelemetry_BothFlushesBothSucceed() var shutdownActions = new List(); var mockApp = CreateMockApp(a => shutdownActions.Add(a)); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); // Act var result = mockApp.OnShutdownFlushOpenTelemetry(); shutdownActions.Should().HaveCount(2); - await shutdownActions[0].Invoke(mockServiceProvider, CancellationToken.None); - await shutdownActions[1].Invoke(mockServiceProvider, CancellationToken.None); + await shutdownActions[0].Invoke(mockContext); + await shutdownActions[1].Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -432,14 +433,14 @@ public async Task OnShutdownFlushOpenTelemetry_TracerFailsButMeterSucceeds() options => options.TracerShouldSucceed = false ); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); // Act var result = mockApp.OnShutdownFlushOpenTelemetry(); shutdownActions.Should().HaveCount(2); - await shutdownActions[0].Invoke(mockServiceProvider, CancellationToken.None); - await shutdownActions[1].Invoke(mockServiceProvider, CancellationToken.None); + await shutdownActions[0].Invoke(mockContext); + await shutdownActions[1].Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -475,14 +476,14 @@ public async Task OnShutdownFlushOpenTelemetry_MeterFailsButTracerSucceeds() options => options.MeterShouldSucceed = false ); - var mockServiceProvider = Substitute.For(); + var mockContext = Substitute.For(); // Act var result = mockApp.OnShutdownFlushOpenTelemetry(); shutdownActions.Should().HaveCount(2); - await shutdownActions[0].Invoke(mockServiceProvider, CancellationToken.None); - await shutdownActions[1].Invoke(mockServiceProvider, CancellationToken.None); + await shutdownActions[0].Invoke(mockContext); + await shutdownActions[1].Invoke(mockContext); // Assert result.Should().Be(mockApp); @@ -522,15 +523,15 @@ public async Task OnShutdownFlushOpenTelemetry_BothFlushesTimeout() } ); - var mockServiceProvider = Substitute.For(); - var cancellationToken = new CancellationToken(true); + var mockContext = Substitute.For(); + mockContext.CancellationToken.Returns(new CancellationToken(true)); // Act var result = mockApp.OnShutdownFlushOpenTelemetry(); shutdownActions.Should().HaveCount(2); - await shutdownActions[0].Invoke(mockServiceProvider, cancellationToken); - await shutdownActions[1].Invoke(mockServiceProvider, cancellationToken); + await shutdownActions[0].Invoke(mockContext); + await shutdownActions[1].Invoke(mockContext); // Assert result.Should().Be(mockApp); From 27d6ea26ebf40e9ec5be97ef4f3169491d28000e Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:21:18 -0500 Subject: [PATCH 24/27] refactor(unit-tests): update `LambdaShutdownDelegate` in shutdown tests - Replaced `IServiceProvider` and `CancellationToken` usage with `ILambdaLifecycleContext` in test cases. - Simplified lambda signature in shutdown handler to improve consistency with recent changes. --- ...nsImplicitVoid#LambdaHandler.g.verified.cs | 6 +++-- ..._MultipleCalls#LambdaHandler.g.verified.cs | 22 ++++++++++--------- ...utdown_NoInput#LambdaHandler.g.verified.cs | 6 +++-- ...UnexpectedType#LambdaHandler.g.verified.cs | 6 +++-- ...ectedTypeAsync#LambdaHandler.g.verified.cs | 6 +++-- ...pectedTypeTask#LambdaHandler.g.verified.cs | 6 +++-- ...eferenceInputs#LambdaHandler.g.verified.cs | 10 +++++---- ...bleKindOfInput#LambdaHandler.g.verified.cs | 18 ++++++++------- ...PrimitiveInput#LambdaHandler.g.verified.cs | 10 +++++---- .../VerifyTests/OnShutdownVerifyTests.cs | 2 +- 10 files changed, 55 insertions(+), 37 deletions(-) diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs index 8d336389..13ed3e0f 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Action)handler; + var castHandler = Cast(handler, void () => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { castHandler.Invoke(); return Task.CompletedTask; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs index 44543c55..c6800493 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs @@ -46,11 +46,11 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return response; @@ -64,16 +64,16 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor1( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string? arg0, global::IService? arg1) => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { // ParameterInfo { Type = string?, Name = x, Source = Service, IsNullable = True, IsOptional = False} - var arg0 = serviceProvider.GetService(); + var arg0 = context.ServiceProvider.GetService(); // ParameterInfo { Type = global::IService?, Name = y, Source = Service, IsNullable = True, IsOptional = False} - var arg1 = serviceProvider.GetService(); + var arg1 = context.ServiceProvider.GetService(); var response = castHandler.Invoke(arg0, arg1); return response; } @@ -86,19 +86,21 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor2( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string arg0, int arg1) => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { // ParameterInfo { Type = string, Name = x, Source = Service, IsNullable = False, IsOptional = False} - var arg0 = serviceProvider.GetRequiredService(); + var arg0 = context.ServiceProvider.GetRequiredService(); // ParameterInfo { Type = int, Name = y, Source = Service, IsNullable = False, IsOptional = False} - var arg1 = serviceProvider.GetRequiredService(); + var arg1 = context.ServiceProvider.GetRequiredService(); var response = castHandler.Invoke(arg0, arg1); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs index c41f0702..e0d5d6bd 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { var response = castHandler.Invoke(); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs index f463885d..f1209d2e 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs @@ -46,15 +46,17 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, string () => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { castHandler.Invoke(); return Task.CompletedTask; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs index 6c047447..77a0abb7 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs @@ -46,14 +46,16 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnShutdown(OnShutdown); - async Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + async Task OnShutdown(ILambdaLifecycleContext context) { await castHandler.Invoke(); } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs index 08fc3161..8cbc8789 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs @@ -46,14 +46,16 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func>)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task () => throw null!); return application.OnShutdown(OnShutdown); - async Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + async Task OnShutdown(ILambdaLifecycleContext context) { await castHandler.Invoke(); } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs index 9c14af0f..f7682bcd 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs @@ -46,19 +46,21 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string? arg0, global::IService? arg1) => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { // ParameterInfo { Type = string?, Name = x, Source = Service, IsNullable = True, IsOptional = False} - var arg0 = serviceProvider.GetService(); + var arg0 = context.ServiceProvider.GetService(); // ParameterInfo { Type = global::IService?, Name = y, Source = Service, IsNullable = True, IsOptional = False} - var arg1 = serviceProvider.GetService(); + var arg1 = context.ServiceProvider.GetService(); var response = castHandler.Invoke(arg0, arg1); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs index cf2fff7a..69499e26 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs @@ -46,29 +46,31 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (global::System.Threading.CancellationToken arg0, global::IService arg1, global::IService? arg2, global::IService arg3, global::IService? arg4) => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { - if (serviceProvider.GetService() is not IServiceProviderIsKeyedService) + if (context.ServiceProvider.GetService() is not IServiceProviderIsKeyedService) { throw new InvalidOperationException($"Unable to resolve service referenced by {nameof(FromKeyedServicesAttribute)}. The service provider doesn't support keyed services."); } // ParameterInfo { Type = global::System.Threading.CancellationToken, Name = token, Source = CancellationToken, IsNullable = False, IsOptional = False} - var arg0 = cancellationToken; + var arg0 = context.CancellationToken; // ParameterInfo { Type = global::IService, Name = service1, Source = KeyedService, IsNullable = False, IsOptional = False, KeyedServiceKeyInfo { DisplayValue = "key1", Type = string, BaseType = object } } - var arg1 = serviceProvider.GetRequiredKeyedService("key1"); + var arg1 = context.ServiceProvider.GetRequiredKeyedService("key1"); // ParameterInfo { Type = global::IService?, Name = service2, Source = KeyedService, IsNullable = True, IsOptional = False, KeyedServiceKeyInfo { DisplayValue = "key2", Type = string, BaseType = object } } - var arg2 = serviceProvider.GetKeyedService("key2"); + var arg2 = context.ServiceProvider.GetKeyedService("key2"); // ParameterInfo { Type = global::IService, Name = service3, Source = Service, IsNullable = False, IsOptional = False} - var arg3 = serviceProvider.GetRequiredService(); + var arg3 = context.ServiceProvider.GetRequiredService(); // ParameterInfo { Type = global::IService?, Name = service4, Source = Service, IsNullable = True, IsOptional = False} - var arg4 = serviceProvider.GetService(); + var arg4 = context.ServiceProvider.GetService(); var response = castHandler.Invoke(arg0, arg1, arg2, arg3, arg4); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs index c3617add..4b673dc3 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs @@ -46,19 +46,21 @@ internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( Delegate handler ) { - var castHandler = (global::System.Func)handler; + var castHandler = Cast(handler, global::System.Threading.Tasks.Task (string arg0, int arg1) => throw null!); return application.OnShutdown(OnShutdown); - Task OnShutdown(IServiceProvider serviceProvider, CancellationToken cancellationToken) + Task OnShutdown(ILambdaLifecycleContext context) { // ParameterInfo { Type = string, Name = x, Source = Service, IsNullable = False, IsOptional = False} - var arg0 = serviceProvider.GetRequiredService(); + var arg0 = context.ServiceProvider.GetRequiredService(); // ParameterInfo { Type = int, Name = y, Source = Service, IsNullable = False, IsOptional = False} - var arg1 = serviceProvider.GetRequiredService(); + var arg1 = context.ServiceProvider.GetRequiredService(); var response = castHandler.Invoke(arg0, arg1); return response; } } + + private static T Cast(Delegate d, T _) where T : Delegate => (T)d; } } \ No newline at end of file diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnShutdownVerifyTests.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnShutdownVerifyTests.cs index 98a0e8ef..9332452b 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnShutdownVerifyTests.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/VerifyTests/OnShutdownVerifyTests.cs @@ -15,7 +15,7 @@ await GeneratorTestHelpers.Verify( var lambda = builder.Build(); lambda.OnShutdown( - async (services, token) => + async (context) => { return; } From ee30de2c72bff0b56c8dfff89868232b1b0793a1 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:22:53 -0500 Subject: [PATCH 25/27] refactor(source-generators): remove commented location hints from templates - Removed `// Location: ...` comments from `GenericHandler.scriban` and `MapHandler.scriban`. - Simplified template files by eliminating unnecessary inline documentation. --- .../Templates/GenericHandler.scriban | 1 - .../Templates/MapHandler.scriban | 1 - ...est_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs | 1 - ...Async_ReturnTaskString_TypeCast#LambdaHandler.g.verified.cs | 1 - ...t_BlockLambda_NoReturn_TypeCast#LambdaHandler.g.verified.cs | 1 - ...BlockLambda_NoTypeInfo_TypeCast#LambdaHandler.g.verified.cs | 1 - ..._BlockLambda_ReturnExplicitType#LambdaHandler.g.verified.cs | 1 - ...ckLambda_ReturnImplicitNullable#LambdaHandler.g.verified.cs | 1 - ...s.Test_BlockLambda_ReturnString#LambdaHandler.g.verified.cs | 1 - ...st_BlockLambda_ReturnTaskString#LambdaHandler.g.verified.cs | 1 - ...lockLambda_ReturnsTask_TypeCast#LambdaHandler.g.verified.cs | 1 - ...Test_BlockLambda_StreamResponse#LambdaHandler.g.verified.cs | 1 - ...Tests.Test_BlockLambda_TypeCast#LambdaHandler.g.verified.cs | 1 - ...TypeCast_InputFromKeyedServices#LambdaHandler.g.verified.cs | 1 - ...Lambda_AsksForCancellationToken#LambdaHandler.g.verified.cs | 1 - ...ncellationTokenAndLambdaContext#LambdaHandler.g.verified.cs | 1 - ...lationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs | 1 - ...Lambda_Async_ReturnExplicitTask#LambdaHandler.g.verified.cs | 1 - ...mbda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs | 1 - ...t_ExpressionLambda_ExplicitVoid#LambdaHandler.g.verified.cs | 1 - ..._ExpressionLambda_InputDi_Async#LambdaHandler.g.verified.cs | 1 - ...ionLambda_InputDi_AsyncAndAwait#LambdaHandler.g.verified.cs | 1 - ...ntAndResponseDifferentNamespace#LambdaHandler.g.verified.cs | 1 - ...st_ExpressionLambda_InputStream#LambdaHandler.g.verified.cs | 1 - ...pressionLambda_NoInput_NoOutput#LambdaHandler.g.verified.cs | 1 - ...bda_NoInput_ReturnGenericObject#LambdaHandler.g.verified.cs | 1 - ...NoInput_ReturnNullablePrimitive#LambdaHandler.g.verified.cs | 1 - ...sionLambda_NoInput_ReturnString#LambdaHandler.g.verified.cs | 1 - ...bleInput_ReturnExplicitNullable#LambdaHandler.g.verified.cs | 1 - ...bleInput_ReturnImplicitNullable#LambdaHandler.g.verified.cs | 1 - ...essionLambda_ReturnExplicitTask#LambdaHandler.g.verified.cs | 1 - ...essionLambda_ReturnExplicitType#LambdaHandler.g.verified.cs | 1 - ...KeyedService_FloatingPointTypes#LambdaHandler.g.verified.cs | 1 - ...est_KeyedService_IntAndLongKeys#LambdaHandler.g.verified.cs | 1 - ...ts.Test_KeyedService_OtherTypes#LambdaHandler.g.verified.cs | 1 - ..._KeyedService_SmallIntegerTypes#LambdaHandler.g.verified.cs | 1 - ..._KeyedService_StringAndEnumKeys#LambdaHandler.g.verified.cs | 1 - ...yedService_UnsignedIntegerTypes#LambdaHandler.g.verified.cs | 1 - ...ts.Test_MethodHandler_AsyncVoid#LambdaHandler.g.verified.cs | 1 - ...dHandler_Async_ReturnTaskString#LambdaHandler.g.verified.cs | 1 - ..._BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs | 1 - ...ethodHandler_BlockBody_TypeCast#LambdaHandler.g.verified.cs | 1 - ...ndler_BlockBody_TypeCast_Static#LambdaHandler.g.verified.cs | 1 - ..._MethodHandler_NoInput_NoOutput#LambdaHandler.g.verified.cs | 1 - ...s.Test_MethodHandler_ReturnTask#LambdaHandler.g.verified.cs | 1 - ..._MethodHandler_ReturnTaskString#LambdaHandler.g.verified.cs | 1 - ...ndler_TypeCast_ExtraParentheses#LambdaHandler.g.verified.cs | 1 - ..._OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs | 1 - ...OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs | 1 - ...yncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs | 1 - ....Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs | 1 - ...Tests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs | 3 --- ...ts.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs | 1 - ..._OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs | 1 - ....Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs | 1 - ...t_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs | 1 - ...nput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs | 1 - ...Input_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs | 1 - ...t_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs | 1 - ...NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs | 1 - ...it_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs | 1 - ...ests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs | 1 - ...BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs | 1 - ...s.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs | 3 --- ...fyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs | 1 - ...wn_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs | 1 - ...Input_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs | 1 - ...oInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs | 1 - ...NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs | 1 - ...wn_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs | 1 - ....Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs | 1 - 71 files changed, 75 deletions(-) diff --git a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban index a2551418..6773aac6 100644 --- a/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban +++ b/src/MinimalLambda.SourceGenerators/Templates/GenericHandler.scriban @@ -12,7 +12,6 @@ namespace MinimalLambda.Generated file static class GeneratedLambda{{ name }}BuilderExtensions { {{~ for call in calls ~}} - // Location: {{ call.location.display_location }} [InterceptsLocation({{ call.location.version }}, "{{ call.location.data }}")] internal static {{ call.target_type }} {{ name }}Interceptor{{ for.index }}{{ call.generic_parameters }}( this {{ call.target_type }} application, diff --git a/src/MinimalLambda.SourceGenerators/Templates/MapHandler.scriban b/src/MinimalLambda.SourceGenerators/Templates/MapHandler.scriban index 4d829209..3861e045 100644 --- a/src/MinimalLambda.SourceGenerators/Templates/MapHandler.scriban +++ b/src/MinimalLambda.SourceGenerators/Templates/MapHandler.scriban @@ -15,7 +15,6 @@ namespace MinimalLambda.Generated private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; {{~ for call in map_handler_calls ~}} - // Location: {{ call.location.display_location }} [InterceptsLocation({{ call.location.version }}, "{{ call.location.data }}")] internal static ILambdaInvocationBuilder MapHandlerInterceptor{{ for.index }}( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs index e1f72688..8865e8ab 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_AllInputSources#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(14,8) [InterceptsLocation(1, "Tx1x72WT0aa+xpOr41o/dzsBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_Async_ReturnTaskString_TypeCast#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_Async_ReturnTaskString_TypeCast#LambdaHandler.g.verified.cs index 766b7934..1d67804f 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_Async_ReturnTaskString_TypeCast#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_Async_ReturnTaskString_TypeCast#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "RRgc5MNn+AL4pWTKQhrXsLYAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoReturn_TypeCast#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoReturn_TypeCast#LambdaHandler.g.verified.cs index d675980b..0e826285 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoReturn_TypeCast#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoReturn_TypeCast#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "x0XA1nde6vAUjFMeY2ZDTdoAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoTypeInfo_TypeCast#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoTypeInfo_TypeCast#LambdaHandler.g.verified.cs index a84f597d..179c0121 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoTypeInfo_TypeCast#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_NoTypeInfo_TypeCast#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "uvqLvSSclxUXzwz2YmfzRrwAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnExplicitType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnExplicitType#LambdaHandler.g.verified.cs index 341b6b4b..acfd56a5 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnExplicitType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnExplicitType#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "nm5FtUI+NJquLXB1CZ0sIswAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnImplicitNullable#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnImplicitNullable#LambdaHandler.g.verified.cs index 6e4fdd97..a993341e 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnImplicitNullable#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnImplicitNullable#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(8,8) [InterceptsLocation(1, "utXmh7WLuYyG7VwRDFaLbq4AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnString#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnString#LambdaHandler.g.verified.cs index e85d05a1..250a9a86 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnString#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnString#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(8,8) [InterceptsLocation(1, "YyltEHxaNav+M48OGFvSga4AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnTaskString#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnTaskString#LambdaHandler.g.verified.cs index bafd7788..bbe64432 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnTaskString#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnTaskString#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(12,8) [InterceptsLocation(1, "o/ULBbkPcz16o9tbQ0tOEPcAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnsTask_TypeCast#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnsTask_TypeCast#LambdaHandler.g.verified.cs index 0816cbf6..0150e0e3 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnsTask_TypeCast#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_ReturnsTask_TypeCast#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "2aTdwJdHl473WaMveiNuirYAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_StreamResponse#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_StreamResponse#LambdaHandler.g.verified.cs index d814c365..2c471368 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_StreamResponse#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_StreamResponse#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "jPT53Ewh7xx9P9yb1DeyM8AAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast#LambdaHandler.g.verified.cs index b5b5f3b8..bdd18c50 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "SZ39GgPCyw+sAyqV7Y0MlLwAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast_InputFromKeyedServices#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast_InputFromKeyedServices#LambdaHandler.g.verified.cs index d331ced7..73239331 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast_InputFromKeyedServices#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/BlockLambdaVerifyTests.Test_BlockLambda_TypeCast_InputFromKeyedServices#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(11,8) [InterceptsLocation(1, "2G3T5x4NjDpOFGweblm35AoBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationToken#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationToken#LambdaHandler.g.verified.cs index 5556169d..c3cd6db9 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationToken#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationToken#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "uuDt15jObMe1Qq8s3gllzMYAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs index 6f330d17..9441ab08 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaContext#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "E0m79hZz+OhoP5DYhe70YeAAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs index 8e8104ef..d8b5ec2f 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_AsksForCancellationTokenAndLambdaHostContext#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "FpwfFi8HLWXcIbdaQfstO+AAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_Async_ReturnExplicitTask#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_Async_ReturnExplicitTask#LambdaHandler.g.verified.cs index 11082dca..14919bb0 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_Async_ReturnExplicitTask#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_Async_ReturnExplicitTask#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "cT3iuq87IWiCDKzjFXbX3swAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs index 92249518..707a0438 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ComplexInput_ComplexOutput#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "k8jU1POB8TXl/XtywGzhweYAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ExplicitVoid#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ExplicitVoid#LambdaHandler.g.verified.cs index 2f19755a..268fc544 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ExplicitVoid#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ExplicitVoid#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(11,8) [InterceptsLocation(1, "mCw0TmMoKLslRA4zotAzTtkAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_Async#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_Async#LambdaHandler.g.verified.cs index c9a53e08..904e85dc 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_Async#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_Async#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "RYU1ACjUCJAF6VKP6xz4f68AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait#LambdaHandler.g.verified.cs index 67fc5e20..d24fe6b0 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "YAxktVM2tLACcLf16mEVcc0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait_EventAndResponseDifferentNamespace#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait_EventAndResponseDifferentNamespace#LambdaHandler.g.verified.cs index 31044848..0d0e02e5 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait_EventAndResponseDifferentNamespace#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputDi_AsyncAndAwait_EventAndResponseDifferentNamespace#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(11,8) [InterceptsLocation(1, "g8LHgWNG7I4SppTaP2NXcuAAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputStream#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputStream#LambdaHandler.g.verified.cs index 4a559981..65008b0d 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputStream#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_InputStream#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "j1cZzS1JRw4YpXVdsmK4icAAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_NoOutput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_NoOutput#LambdaHandler.g.verified.cs index fc457c5e..89a04736 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_NoOutput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_NoOutput#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "3CWFbmqnBB4YxhpsZbBulq8AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnGenericObject#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnGenericObject#LambdaHandler.g.verified.cs index ec9235fe..83e02a44 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnGenericObject#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnGenericObject#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(8,8) [InterceptsLocation(1, "G4Om3+ihXcYexFMvnSQvJ64AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnNullablePrimitive#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnNullablePrimitive#LambdaHandler.g.verified.cs index 05be05e2..97726f06 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnNullablePrimitive#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnNullablePrimitive#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(8,8) [InterceptsLocation(1, "JhcPD8PsJIdWe6XLFN10+a4AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnString#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnString#LambdaHandler.g.verified.cs index a5f9ac70..aed9f2fd 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnString#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NoInput_ReturnString#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "in+uvLWWJ/AtKXn3ATT2fa8AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnExplicitNullable#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnExplicitNullable#LambdaHandler.g.verified.cs index 41ec5ba6..17b19dd9 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnExplicitNullable#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnExplicitNullable#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(8,8) [InterceptsLocation(1, "GzrEvlSIcRHrVreaVlX6r64AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnImplicitNullable#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnImplicitNullable#LambdaHandler.g.verified.cs index df57ea28..d13f96a0 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnImplicitNullable#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_NullableInput_ReturnImplicitNullable#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(8,8) [InterceptsLocation(1, "FyRpi+O01Le5sodA43elIa4AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitTask#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitTask#LambdaHandler.g.verified.cs index 3a6e8de8..8472525b 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitTask#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitTask#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "KJD4PMoAebDtIgB60tZNgswAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitType#LambdaHandler.g.verified.cs index dd0d0ee4..3104180d 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/ExpressionLambdaVerifyTests.Test_ExpressionLambda_ReturnExplicitType#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "Omlg4OEyk26g8wXWjLDFPcwAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_FloatingPointTypes#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_FloatingPointTypes#LambdaHandler.g.verified.cs index a6929d4c..1d366b09 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_FloatingPointTypes#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_FloatingPointTypes#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(12,8) [InterceptsLocation(1, "oOoX2Z8lm6heONKgRuSEMVoBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_IntAndLongKeys#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_IntAndLongKeys#LambdaHandler.g.verified.cs index 84c351ac..46164809 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_IntAndLongKeys#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_IntAndLongKeys#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(12,8) [InterceptsLocation(1, "UQNgECJiz6f37Kqrohi6T1YBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_OtherTypes#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_OtherTypes#LambdaHandler.g.verified.cs index af67de00..7c3a39d8 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_OtherTypes#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_OtherTypes#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(14,8) [InterceptsLocation(1, "hmegcgWk2t+EeA09rekjfN0BAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_SmallIntegerTypes#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_SmallIntegerTypes#LambdaHandler.g.verified.cs index db0706ec..9deaac58 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_SmallIntegerTypes#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_SmallIntegerTypes#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(13,8) [InterceptsLocation(1, "hw5rLqU36tq+UKKZjsYo+6QBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_StringAndEnumKeys#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_StringAndEnumKeys#LambdaHandler.g.verified.cs index 9e245e3c..c02e79a2 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_StringAndEnumKeys#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_StringAndEnumKeys#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(13,8) [InterceptsLocation(1, "+h6TuNWWRrZ6456NGR3gY68BAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_UnsignedIntegerTypes#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_UnsignedIntegerTypes#LambdaHandler.g.verified.cs index 8243d625..2004666c 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_UnsignedIntegerTypes#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/KeyedServiceVerifyTests.Test_KeyedService_UnsignedIntegerTypes#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(13,8) [InterceptsLocation(1, "AxgJhn/c6EE+EjInktbZjJsBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_AsyncVoid#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_AsyncVoid#LambdaHandler.g.verified.cs index c4c248b5..c1ce7060 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_AsyncVoid#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_AsyncVoid#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "KboCfbbG13nfDrp0SLg8M7wAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_Async_ReturnTaskString#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_Async_ReturnTaskString#LambdaHandler.g.verified.cs index 92ed4fe2..513a1e18 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_Async_ReturnTaskString#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_Async_ReturnTaskString#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "ZkrKvKVefW15Q5g1yuxuRcwAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs index 079b4daa..1ff128c3 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_InputDiKeyedServices#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(11,8) [InterceptsLocation(1, "WvA1V6ThyZ94LdZnpGUzR/kAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast#LambdaHandler.g.verified.cs index 2cfd58fe..c5be4fbf 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "9iVXmQzdmOJRzQb10S6vbbwAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast_Static#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast_Static#LambdaHandler.g.verified.cs index a36b2475..dd8a90b8 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast_Static#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_BlockBody_TypeCast_Static#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "WkNvIuTbAdwaZik4NmqZnLwAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_NoInput_NoOutput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_NoInput_NoOutput#LambdaHandler.g.verified.cs index 0711fa78..444d7326 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_NoInput_NoOutput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_NoInput_NoOutput#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "+Lz+jm6gwTdwCiVkSNzQ87wAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTask#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTask#LambdaHandler.g.verified.cs index 95f7b33b..531f67fb 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTask#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTask#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "JJAuncCVlvzsQmF1nMYHRMwAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTaskString#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTaskString#LambdaHandler.g.verified.cs index 529a3a25..bb083dac 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTaskString#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_ReturnTaskString#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "/Yux3FXySiMlCW6XCvraq8wAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_TypeCast_ExtraParentheses#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_TypeCast_ExtraParentheses#LambdaHandler.g.verified.cs index 2b862a26..6cc62825 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_TypeCast_ExtraParentheses#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/MethodHandlerVerifyTests.Test_MethodHandler_TypeCast_ExtraParentheses#LambdaHandler.g.verified.cs @@ -42,7 +42,6 @@ file static class GeneratedLambdaInvocationBuilderExtensions private const string EventFeatureProviderKey = "__EventFeatureProvider"; private const string ResponseFeatureProviderKey = "__ResponseFeatureProvider"; - // Location: InputFile.cs(9,8) [InterceptsLocation(1, "B3NwPy0yR+xRbgA9x8f/e7wAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaInvocationBuilder MapHandlerInterceptor0( this ILambdaInvocationBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs index be774481..3916e9aa 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_ExplicitReturnTypeAsync#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "q1uiaF3q8+xYajQEZyxaiM0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs index e8e633fc..e02e2153 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDi#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "GvWtmkGvhj2sJm4/rXiUGc0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs index e0cf07b7..6b3c3800 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_AsyncAndDiAndReturnUnexpectedType#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "8o56Zwu2oVW8FXpGxJSFvc0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs index e11612fd..059d0efa 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MethodHandler_NoDi#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(12,8) [InterceptsLocation(1, "3ivf5JplhmGDGF7iXdWVSucAAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs index 69f8a6b6..88ccff0f 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_MultipleCalls#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "gOjUxL7brRqHQuY3oQ1zfc0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, @@ -57,7 +56,6 @@ Task OnInit(ILambdaLifecycleContext context) } } - // Location: InputFile.cs(15,8) [InterceptsLocation(1, "gOjUxL7brRqHQuY3oQ1zfRUBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor1( this ILambdaOnInitBuilder application, @@ -79,7 +77,6 @@ Task OnInit(ILambdaLifecycleContext context) } } - // Location: InputFile.cs(22,8) [InterceptsLocation(1, "gOjUxL7brRqHQuY3oQ1zfXoBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor2( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs index 48303344..5d5f90b4 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_NoOutput#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "muLM5AWLiyZcBDFwDjSMbc0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs index 04368d31..160a2e50 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnAsyncBool#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "itVOIXgsd2/a5q0mYhXydM0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs index dedf0c34..bad28be5 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnBool#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "dCq2ERewPXxHvi/4iSh/m80AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs index 44a29c5b..b518ceb4 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedType#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "7+o+H0MkQG+24GOQUPBdDs0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs index d8d02a84..9264f56b 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeAsync#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "pi9PolKCGMrmFvoC3ft/Oc0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs index f720cab1..eb832568 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnNotExpectedTypeTask#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "Vg2L2eBzhOCM6KRY6cER2c0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs index e3ab2f89..38cfdad4 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NoInput_ReturnTaskBool#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "cTRqoX+dJLMMKMOCOmOufs0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs index 459deb25..ff69dd98 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "dITS7/hnxk7n1XWH1BHx4s0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs index be02d8fd..d46fb21d 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(12,8) [InterceptsLocation(1, "s9lx/eNP9F4h61w7TOvQPRUBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs index cadd85a3..4cfbb8af 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnInitVerifyTests.Test_OnInit_PrimitiveInput#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnInitBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "8J01folJ0MDOTLxLNRx4fs0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnInitBuilder OnInitInterceptor0( this ILambdaOnInitBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs index 13ed3e0f..e1ca9637 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_BlockLambda_ReturnsImplicitVoid#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "lPDnfssMibsxhX79gLd2lL0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs index c6800493..43510c7f 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_MultipleCalls#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "W852isYQO43ObWn6kxnU5s0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, @@ -57,7 +56,6 @@ Task OnShutdown(ILambdaLifecycleContext context) } } - // Location: InputFile.cs(15,8) [InterceptsLocation(1, "W852isYQO43ObWn6kxnU5hABAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor1( this ILambdaOnShutdownBuilder application, @@ -79,7 +77,6 @@ Task OnShutdown(ILambdaLifecycleContext context) } } - // Location: InputFile.cs(22,8) [InterceptsLocation(1, "W852isYQO43ObWn6kxnU5nsBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor2( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs index e0d5d6bd..c432fdb9 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "F/zSODBMGX3Xez9u/iwpl80AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs index f1209d2e..63388d28 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedType#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "Cr7Neg3slUnAi5SjcvJU580AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs index 77a0abb7..25554d6a 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeAsync#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "YWaX0vtU1wLdNqf9cuGdFM0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs index 8cbc8789..8b42a3b8 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NoInput_ReturnUnexpectedTypeTask#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "12DeS9LwHN3iO8NwFisQBs0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs index f7682bcd..a73d512a 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_NullableValueAndReferenceInputs#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "BGCXXs9bVPwLCAUaU8Kkds0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs index 69499e26..ad12af6c 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_OneOfEachPossibleKindOfInput#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(12,8) [InterceptsLocation(1, "ZhdnggwSuJq0NpRZew7QhhUBAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, diff --git a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs index 4b673dc3..c50d3b1c 100644 --- a/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs +++ b/tests/MinimalLambda.SourceGenerators.UnitTests/Snapshots/OnShutdownVerifyTests.Test_OnShutdown_PrimitiveInput#LambdaHandler.g.verified.cs @@ -39,7 +39,6 @@ namespace MinimalLambda.Generated [GeneratedCode("MinimalLambda.SourceGenerators", "0.0.0")] file static class GeneratedLambdaOnShutdownBuilderExtensions { - // Location: InputFile.cs(10,8) [InterceptsLocation(1, "cuXlRiXWvhKK6Ao4rCbyic0AAABJbnB1dEZpbGUuY3M=")] internal static ILambdaOnShutdownBuilder OnShutdownInterceptor0( this ILambdaOnShutdownBuilder application, From 5ae79659fa4bf0f3de8358a824d070dfb9a68e14 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 19:34:13 -0500 Subject: [PATCH 26/27] feat(minimal-lambda): add shared properties support for Init and Shutdown builders - Integrated `Properties` dictionary into `ILambdaOnInitBuilder` and `ILambdaOnShutdownBuilder`. - Enabled propagation of shared properties between lifecycle handlers during Init and Shutdown. --- src/MinimalLambda/Builder/LambdaApplicationBuilder.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs index 66a4f15c..5f296a5f 100644 --- a/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs +++ b/src/MinimalLambda/Builder/LambdaApplicationBuilder.cs @@ -310,6 +310,9 @@ private void ConfigureOnInitBuilder(ILambdaOnInitBuilder builder) foreach (var handlers in _builtApplication.InitHandlers) builder.OnInit(handlers); + + foreach (var property in ((ILambdaOnInitBuilder)_builtApplication).Properties) + builder.Properties[property.Key] = property.Value; } private void ConfigureOnShutdownBuilder(ILambdaOnShutdownBuilder builder) @@ -319,5 +322,8 @@ private void ConfigureOnShutdownBuilder(ILambdaOnShutdownBuilder builder) foreach (var handlers in _builtApplication.ShutdownHandlers) builder.OnShutdown(handlers); + + foreach (var property in ((ILambdaOnShutdownBuilder)_builtApplication).Properties) + builder.Properties[property.Key] = property.Value; } } From e6894de2a762ff2d77b2557a4488a4601069e215 Mon Sep 17 00:00:00 2001 From: Jonas Ha Date: Tue, 16 Dec 2025 20:18:07 -0500 Subject: [PATCH 27/27] feat(docs): improve lifecycle management and DI guides - Updated lifecycle management guide to include `ILambdaLifecycleContext` usage and DI patterns. - Added examples for direct DI, AWS metadata access, state sharing, and keyed services in OnInit handlers. - Enhanced dependency injection guide with source-generated DI support for OnInit and OnShutdown. - Expanded core concepts with lifecycle context access patterns and practical usage scenarios. --- docs/getting-started/core-concepts.md | 11 +++ docs/guides/dependency-injection.md | 54 ++++++++++++-- docs/guides/lifecycle-management.md | 102 ++++++++++++++++++++++++-- 3 files changed, 154 insertions(+), 13 deletions(-) diff --git a/docs/getting-started/core-concepts.md b/docs/getting-started/core-concepts.md index 25998bd2..522efddc 100644 --- a/docs/getting-started/core-concepts.md +++ b/docs/getting-started/core-concepts.md @@ -85,6 +85,17 @@ lambda.OnShutdown(async ( }); ``` +### Lifecycle Context Access + +Both OnInit and OnShutdown handlers support rich dependency injection patterns: + +- **Inject services directly**: `(ICache cache, ILogger logger, CancellationToken ct)` – Recommended for most scenarios +- **Access AWS metadata**: `(ILambdaLifecycleContext context)` – When you need environment information like function name, region, memory size, or initialization type +- **Combine both**: `(ILambdaLifecycleContext context, ICache cache)` – Mix context access with direct service injection +- **Use keyed services**: `([FromKeyedServices("key")] IService service)` – Resolve services registered with specific keys + +The `ILambdaLifecycleContext` interface provides AWS environment metadata, a `Properties` dictionary for sharing state between handlers, and access to the scoped `ServiceProvider`. See [Lifecycle Management](../guides/lifecycle-management.md) for detailed patterns and examples. + ### Lifecycle Timeline ```mermaid diff --git a/docs/guides/dependency-injection.md b/docs/guides/dependency-injection.md index 0366fa98..c8b5bfe8 100644 --- a/docs/guides/dependency-injection.md +++ b/docs/guides/dependency-injection.md @@ -74,23 +74,63 @@ If your handler doesn't need the Lambda payload, omit the `[FromEvent]` paramete remaining time when creating the token. - Always pass it down to outbound SDK calls and database queries so you can stop work cleanly. -## Middleware and Lifecycle Hooks +## Middleware and Lifecycle Hooks: Source-Generated DI - Middleware receives the invocation scope via the `ILambdaHostContext` argument. Resolve services with `context.ServiceProvider` or create reusable middleware classes with constructor injection. -- `OnInit` and `OnShutdown` handlers run outside the normal invocation scope but each one executes - inside its own scoped service provider so you can warm caches, seed connections, or flush telemetry - without leaking per-invocation services. +- `OnInit` and `OnShutdown` handlers now use the same source-generated dependency injection as your main + handlers. Each executes inside its own scoped service provider so you can warm caches, seed connections, + or flush telemetry without leaking per-invocation services. -```csharp title="OnInit" -lambda.OnInit(async (services, ct) => +OnInit and OnShutdown handlers support multiple dependency injection patterns: + +```csharp title="Pattern 1: Direct DI (Recommended)" +lambda.OnInit(async (ICache cache, ILogger logger, CancellationToken ct) => { - var cache = services.GetRequiredService(); + logger.LogInformation("Warming cache during cold start"); await cache.WarmUpAsync(ct); return true; }); ``` +Each handler runs in its own scoped service provider, so you can safely resolve scoped services even +outside the invocation pipeline. + +```csharp title="Pattern 2: Using ILambdaLifecycleContext" +lambda.OnInit(async (ILambdaLifecycleContext context, ICache cache) => +{ + var logger = context.ServiceProvider.GetRequiredService>(); + logger.LogInformation( + "Init type: {Type}, Function: {Name}, Memory: {MB}MB", + context.InitializationType, + context.FunctionName, + context.FunctionMemorySize + ); + + await cache.WarmUpAsync(context.CancellationToken); + return true; +}); +``` + +Use `ILambdaLifecycleContext` when you need AWS environment metadata (region, function name, memory size, +initialization type) or want to share data between handlers via the `Properties` dictionary. + +```csharp title="Pattern 3: Keyed Services" +builder.Services.AddKeyedSingleton("redis"); +builder.Services.AddKeyedSingleton("memory"); + +lambda.OnInit(async ( + [FromKeyedServices("redis")] ICache primaryCache, + [FromKeyedServices("memory")] ICache fallbackCache, + CancellationToken ct +) => +{ + await primaryCache.WarmUpAsync(ct); + await fallbackCache.WarmUpAsync(ct); + return true; +}); +``` + ## Configuration and Options Use the standard options pattern for configuration: diff --git a/docs/guides/lifecycle-management.md b/docs/guides/lifecycle-management.md index 719bb10a..5ddb808b 100644 --- a/docs/guides/lifecycle-management.md +++ b/docs/guides/lifecycle-management.md @@ -132,22 +132,112 @@ Both handlers are awaited simultaneously. Keep shutdown work small—only the re OnInit and OnShutdown handlers support the same source-generated dependency injection experience as middleware and handlers: -- Request only what you need. The generated delegate resolves typed parameters (services, keyed services, `ILambdaHostContext`, `CancellationToken`, etc.). +- Request only what you need. The generated delegate resolves typed parameters (services, keyed services, `ILambdaLifecycleContext`, `CancellationToken`, etc.). - `MinimalLambda` creates a new `IServiceScope` for every handler invocation, ensuring scoped services (database units of work, caches) are isolated even though you are outside the invocation pipeline. -- The `IServiceProvider` parameter gives you direct access to the scope for manual resolution when needed. +- Inject `ILambdaLifecycleContext` when you need AWS environment metadata or want to share state via the `Properties` dictionary. For simple scenarios, inject services directly. + +```csharp title="Program.cs - Keyed Services" +builder.Services.AddKeyedSingleton("primary"); +builder.Services.AddKeyedSingleton("secondary"); -```csharp title="Program.cs" lambda.OnInit(async ( - IServiceProvider scope, - KeyedService("primary"), + [FromKeyedServices("primary")] IMyClient primaryClient, + [FromKeyedServices("secondary")] IMyClient secondaryClient, CancellationToken ct ) => { - await MyWarmupAsync(scope, MyClient, ct); + await primaryClient.WarmupAsync(ct); + await secondaryClient.WarmupAsync(ct); + return true; +}); +``` + +## Accessing AWS Environment Information + +When you need AWS environment metadata during initialization or shutdown, inject `ILambdaLifecycleContext`. This interface provides rich context information about the Lambda execution environment beyond what's available in the standard invocation pipeline. + +### Using ILambdaLifecycleContext + +```csharp title="Program.cs - AWS Environment Metadata" +lambda.OnInit(async (ILambdaLifecycleContext context, ILogger logger) => +{ + logger.LogInformation( + "Initializing {FunctionName} v{Version} in {Region}", + context.FunctionName, + context.FunctionVersion, + context.Region + ); + + logger.LogInformation( + "Memory: {Memory}MB, Init type: {InitType}, Elapsed: {Elapsed}ms", + context.FunctionMemorySize, + context.InitializationType, + context.ElapsedTime.TotalMilliseconds + ); + return true; }); ``` +### Sharing State via Properties Dictionary + +The `Properties` dictionary lets you share data between OnInit handlers or pass information from initialization to your invocation handlers. + +```csharp title="Program.cs - State Sharing" +lambda.OnInit(async (ILambdaLifecycleContext context) => +{ + var initStartTime = DateTimeOffset.UtcNow; + context.Properties["InitStartTime"] = initStartTime; + context.Properties["EnvironmentType"] = context.InitializationType; + + return true; +}); + +lambda.OnInit(async (ILambdaLifecycleContext context, ILogger logger) => +{ + if (context.Properties.TryGetValue("InitStartTime", out var startTime)) + { + logger.LogInformation("First handler started at {Time}", startTime); + } + + return true; +}); +``` + +The `Properties` dictionary is backed by a thread-safe `ConcurrentDictionary` and is shared across all OnInit handlers. Properties set during OnInit are also available to invocation handlers via `ILambdaHostContext.Properties`. + +### Available Context Properties + +`ILambdaLifecycleContext` exposes the following properties: + +| Property | Type | Description | +|----------|------|-------------| +| `CancellationToken` | `CancellationToken` | Signals cancellation when `InitTimeout` (OnInit) or `ShutdownDuration - ShutdownDurationBuffer` (OnShutdown) elapses, or when SIGTERM is received | +| `ServiceProvider` | `IServiceProvider` | The scoped service container for this handler invocation. Use for manual service resolution when direct injection isn't sufficient | +| `Properties` | `IDictionary` | Thread-safe dictionary for sharing data between handlers or from OnInit to invocation handlers | +| `ElapsedTime` | `TimeSpan` | Time elapsed since the Lambda execution environment started | +| `Region` | `string?` | AWS region where the function is running (from `AWS_REGION` env var) | +| `ExecutionEnvironment` | `string?` | Runtime identifier like `AWS_Lambda_dotnet8` (from `AWS_EXECUTION_ENV` env var) | +| `FunctionName` | `string?` | Name of the Lambda function (from `AWS_LAMBDA_FUNCTION_NAME` env var) | +| `FunctionMemorySize` | `int?` | Memory allocated to the function in MB (from `AWS_LAMBDA_FUNCTION_MEMORY_SIZE` env var) | +| `FunctionVersion` | `string?` | Version of the function being executed (from `AWS_LAMBDA_FUNCTION_VERSION` env var) | +| `InitializationType` | `string?` | Type of initialization: `on-demand`, `provisioned-concurrency`, `snap-start`, or `lambda-managed-instances` (from `AWS_LAMBDA_INITIALIZATION_TYPE` env var) | +| `LogGroupName` | `string?` | CloudWatch Logs group name (from `AWS_LAMBDA_LOG_GROUP_NAME` env var, not available in SnapStart) | +| `LogStreamName` | `string?` | CloudWatch Logs stream name (from `AWS_LAMBDA_LOG_STREAM_NAME` env var, not available in SnapStart) | +| `TaskRoot` | `string?` | Path to the Lambda function code (from `LAMBDA_TASK_ROOT` env var) | + +All AWS environment properties are nullable because they depend on environment variables set by the Lambda runtime. Most are available during normal execution, but some (like `LogGroupName` and `LogStreamName`) are unavailable in SnapStart functions. + +### When to Use ILambdaLifecycleContext + +Use `ILambdaLifecycleContext` when you need: + +- **AWS environment metadata** – Access region, function name, memory size, or initialization type for logging, metrics, or conditional logic based on the execution environment +- **State sharing** – Pass data between OnInit handlers or from OnInit to invocation handlers via the `Properties` dictionary +- **Manual service resolution** – Access `ServiceProvider` directly for advanced scenarios where parameter injection isn't sufficient + +For simple dependency injection scenarios, prefer injecting services directly as parameters instead of using `ILambdaLifecycleContext.ServiceProvider`. + ## Configuring Lifecycle Behavior Use `ConfigureLambdaHostOptions` to shape lifecycle behavior centrally or bind the same settings from configuration: