Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions .autover/changes/f0d5a912-bcfa-4244-96cb-ac3c847f877c.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"Projects": [
{
"Name": "Amazon.Lambda.AspNetCoreServer",
"Type": "Major",
"ChangelogMessages": [
"[Breaking] Update build targets from .NET 6 and 8 to .NET 8 and 10",
"[Preview] Add support Lambda Response Streaming enabled by setting the EnableResponseStreaming property from the base class AbstractAspNetCoreFunction"
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Changelog message grammar: "Add support Lambda Response Streaming enabled by setting..." is missing "for" and reads awkwardly. Consider rephrasing to something like "[Preview] Add support for Lambda response streaming, enabled by setting the EnableResponseStreaming property on AbstractAspNetCoreFunction" for clarity.

Copilot uses AI. Check for mistakes.
]
},
{
"Name": "Amazon.Lambda.AspNetCoreServer.Hosting",
"Type": "Major",
"ChangelogMessages": [
"[Breaking] Update build targets from .NET 6 and 8 to .NET 8 and 10",
"[Preview] Add support Lambda Response Streaming enabled by setting the EnableResponseStreaming property on the HostingOptions object passed into the AddAWSLambdaHosting method"
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Changelog message grammar: "Add support Lambda Response Streaming enabled by setting..." is missing "for" and would be clearer if rephrased. Consider something like "[Preview] Add support for Lambda response streaming, enabled by setting EnableResponseStreaming on HostingOptions passed to AddAWSLambdaHosting".

Copilot uses AI. Check for mistakes.
]
},
{
"Name": "Amazon.Lambda.Logging.AspNetCore",
"Type": "Major",
"ChangelogMessages": [
"[Breaking] Update build targets from .NET 6 and 8 to .NET 8 and 10"
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<PropertyGroup>
<Description>Package for running ASP.NET Core applications using the Minimal API style as a AWS Lambda function.</Description>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Version>1.10.0</Version>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ namespace Amazon.Lambda.AspNetCoreServer.Hosting;
/// </summary>
public class HostingOptions
{
internal const string ParameterizedPreviewMessage =
"Response streaming is in preview till a new version of .NET Lambda runtime client that supports response streaming " +
"has been deployed to the .NET Lambda managed runtime. Till deployment has been made the feature can be used by deploying as an " +
"executable including the latest version of Amazon.Lambda.RuntimeSupport and setting the \"EnablePreviewFeatures\" in the Lambda " +
"project file to \"true\"";

/// <summary>
/// The ILambdaSerializer used by Lambda to convert the incoming event JSON into the .NET event type and serialize the .NET response type
/// back to JSON to return to Lambda.
Expand All @@ -27,6 +33,14 @@ public class HostingOptions
/// </summary>
public bool IncludeUnhandledExceptionDetailInResponse { get; set; } = false;

/// <summary>
/// When true, the Lambda hosting server will invoke <c>StreamingFunctionHandlerAsync</c>
/// instead of <c>FunctionHandlerAsync</c>, enabling Lambda response streaming.
/// Requires net8.0 or later.
Comment on lines +37 to +39
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

The XML doc for EnableResponseStreaming mentions invoking StreamingFunctionHandlerAsync, but the implementation toggles behavior inside FunctionHandlerAsync via the EnableResponseStreaming property (no StreamingFunctionHandlerAsync method exists). This doc mismatch may confuse users; consider updating the comment to describe the actual behavior (FunctionHandlerAsync switches to streaming mode and returns null while writing to a Lambda response stream).

Suggested change
/// When true, the Lambda hosting server will invoke <c>StreamingFunctionHandlerAsync</c>
/// instead of <c>FunctionHandlerAsync</c>, enabling Lambda response streaming.
/// Requires net8.0 or later.
/// When true, the Lambda hosting server enables Lambda response streaming behavior
/// when invoking <c>FunctionHandlerAsync</c>. In streaming mode,
/// <c>FunctionHandlerAsync</c> writes directly to the Lambda response stream and
/// returns <c>null</c>. Requires net8.0 or later.

Copilot uses AI. Check for mistakes.
/// </summary>
[System.Runtime.Versioning.RequiresPreviewFeatures(ParameterizedPreviewMessage)]
public bool EnableResponseStreaming { get; set; } = false;

/// <summary>
/// Callback invoked after request marshalling to customize the HTTP request feature.
/// Receives the IHttpRequestFeature, Lambda request object, and ILambdaContext.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

namespace Amazon.Lambda.AspNetCoreServer.Hosting.Internal;

#if NET8_0_OR_GREATER
/// <summary>
/// Helper class for storing Requests for
/// <see cref="ServiceCollectionExtensions.AddAWSLambdaBeforeSnapshotRequest"/>
Expand All @@ -14,4 +13,3 @@ internal class GetBeforeSnapshotRequestsCollector
{
public HttpRequestMessage? Request { get; set; }
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,21 @@ public APIGatewayHttpApiV2LambdaRuntimeSupportServer(IServiceProvider servicePro
/// <returns></returns>
protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider)
{
var handler = new APIGatewayHttpApiV2MinimalApi(serviceProvider).FunctionHandlerAsync;
return HandlerWrapper.GetHandlerWrapper(handler, this.Serializer);
var handler = new APIGatewayHttpApiV2MinimalApi(serviceProvider);
#pragma warning disable CA2252
var hostingOptions = serviceProvider.GetService<HostingOptions>();
handler.EnableResponseStreaming = hostingOptions?.EnableResponseStreaming ?? false;
#pragma warning restore CA2252
Func<APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest, ILambdaContext, Task<APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse>> bufferedHandler = handler.FunctionHandlerAsync;
return HandlerWrapper.GetHandlerWrapper(bufferedHandler, this.Serializer);
}

/// <summary>
/// Create the APIGatewayHttpApiV2ProxyFunction passing in the ASP.NET Core application's IServiceProvider
/// </summary>
public class APIGatewayHttpApiV2MinimalApi : APIGatewayHttpApiV2ProxyFunction
{
#if NET8_0_OR_GREATER
private readonly IEnumerable<GetBeforeSnapshotRequestsCollector> _beforeSnapshotRequestsCollectors;
#endif
private readonly HostingOptions? _hostingOptions;

/// <summary>
Expand All @@ -99,9 +102,7 @@ public class APIGatewayHttpApiV2MinimalApi : APIGatewayHttpApiV2ProxyFunction
public APIGatewayHttpApiV2MinimalApi(IServiceProvider serviceProvider)
: base(serviceProvider)
{
#if NET8_0_OR_GREATER
_beforeSnapshotRequestsCollectors = serviceProvider.GetServices<GetBeforeSnapshotRequestsCollector>();
#endif

// Retrieve HostingOptions from service provider (may be null for backward compatibility)
_hostingOptions = serviceProvider.GetService<HostingOptions>();
Expand All @@ -127,14 +128,12 @@ public APIGatewayHttpApiV2MinimalApi(IServiceProvider serviceProvider)
}
}

#if NET8_0_OR_GREATER
protected override IEnumerable<HttpRequestMessage> GetBeforeSnapshotRequests()
{
foreach (var collector in _beforeSnapshotRequestsCollectors)
if (collector.Request != null)
yield return collector.Request;
}
#endif

protected override void PostMarshallRequestFeature(IHttpRequestFeature aspNetCoreRequestFeature, APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
Expand Down Expand Up @@ -208,18 +207,21 @@ public APIGatewayRestApiLambdaRuntimeSupportServer(IServiceProvider serviceProvi
/// <returns></returns>
protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider)
{
var handler = new APIGatewayRestApiMinimalApi(serviceProvider).FunctionHandlerAsync;
return HandlerWrapper.GetHandlerWrapper(handler, this.Serializer);
var handler = new APIGatewayRestApiMinimalApi(serviceProvider);
#pragma warning disable CA2252
var hostingOptions = serviceProvider.GetService<HostingOptions>();
handler.EnableResponseStreaming = hostingOptions?.EnableResponseStreaming ?? false;
#pragma warning restore CA2252
Func<APIGatewayEvents.APIGatewayProxyRequest, ILambdaContext, Task<APIGatewayEvents.APIGatewayProxyResponse>> bufferedHandler = handler.FunctionHandlerAsync;
return HandlerWrapper.GetHandlerWrapper(bufferedHandler, this.Serializer);
}

/// <summary>
/// Create the APIGatewayProxyFunction passing in the ASP.NET Core application's IServiceProvider
/// </summary>
public class APIGatewayRestApiMinimalApi : APIGatewayProxyFunction
{
#if NET8_0_OR_GREATER
private readonly IEnumerable<GetBeforeSnapshotRequestsCollector> _beforeSnapshotRequestsCollectors;
#endif
private readonly HostingOptions? _hostingOptions;

/// <summary>
Expand All @@ -229,9 +231,7 @@ public class APIGatewayRestApiMinimalApi : APIGatewayProxyFunction
public APIGatewayRestApiMinimalApi(IServiceProvider serviceProvider)
: base(serviceProvider)
{
#if NET8_0_OR_GREATER
_beforeSnapshotRequestsCollectors = serviceProvider.GetServices<GetBeforeSnapshotRequestsCollector>();
#endif

// Retrieve HostingOptions from service provider (may be null for backward compatibility)
_hostingOptions = serviceProvider.GetService<HostingOptions>();
Expand All @@ -257,14 +257,12 @@ public APIGatewayRestApiMinimalApi(IServiceProvider serviceProvider)
}
}

#if NET8_0_OR_GREATER
protected override IEnumerable<HttpRequestMessage> GetBeforeSnapshotRequests()
{
foreach (var collector in _beforeSnapshotRequestsCollectors)
if (collector.Request != null)
yield return collector.Request;
}
#endif

protected override void PostMarshallRequestFeature(IHttpRequestFeature aspNetCoreRequestFeature, APIGatewayEvents.APIGatewayProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
Expand Down Expand Up @@ -338,18 +336,21 @@ public ApplicationLoadBalancerLambdaRuntimeSupportServer(IServiceProvider servic
/// <returns></returns>
protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider)
{
var handler = new ApplicationLoadBalancerMinimalApi(serviceProvider).FunctionHandlerAsync;
return HandlerWrapper.GetHandlerWrapper(handler, this.Serializer);
var handler = new ApplicationLoadBalancerMinimalApi(serviceProvider);
#pragma warning disable CA2252
var hostingOptions = serviceProvider.GetService<HostingOptions>();
handler.EnableResponseStreaming = hostingOptions?.EnableResponseStreaming ?? false;
#pragma warning restore CA2252
Func<ApplicationLoadBalancerEvents.ApplicationLoadBalancerRequest, ILambdaContext, Task<ApplicationLoadBalancerEvents.ApplicationLoadBalancerResponse>> bufferedHandler = handler.FunctionHandlerAsync;
return HandlerWrapper.GetHandlerWrapper(bufferedHandler, this.Serializer);
}

/// <summary>
/// Create the ApplicationLoadBalancerFunction passing in the ASP.NET Core application's IServiceProvider
/// </summary>
public class ApplicationLoadBalancerMinimalApi : ApplicationLoadBalancerFunction
{
#if NET8_0_OR_GREATER
private readonly IEnumerable<GetBeforeSnapshotRequestsCollector> _beforeSnapshotRequestsCollectors;
#endif
private readonly HostingOptions? _hostingOptions;

/// <summary>
Expand All @@ -359,9 +360,7 @@ public class ApplicationLoadBalancerMinimalApi : ApplicationLoadBalancerFunction
public ApplicationLoadBalancerMinimalApi(IServiceProvider serviceProvider)
: base(serviceProvider)
{
#if NET8_0_OR_GREATER
_beforeSnapshotRequestsCollectors = serviceProvider.GetServices<GetBeforeSnapshotRequestsCollector>();
#endif

// Retrieve HostingOptions from service provider (may be null for backward compatibility)
_hostingOptions = serviceProvider.GetService<HostingOptions>();
Expand All @@ -387,14 +386,12 @@ public ApplicationLoadBalancerMinimalApi(IServiceProvider serviceProvider)
}
}

#if NET8_0_OR_GREATER
protected override IEnumerable<HttpRequestMessage> GetBeforeSnapshotRequests()
{
foreach (var collector in _beforeSnapshotRequestsCollectors)
if (collector.Request != null)
yield return collector.Request;
}
#endif

protected override void PostMarshallRequestFeature(IHttpRequestFeature aspNetCoreRequestFeature, ApplicationLoadBalancerEvents.ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ public static IServiceCollection AddAWSLambdaHosting(this IServiceCollection ser
return services;
}

#if NET8_0_OR_GREATER
/// <summary>
/// Adds a <see cref="HttpRequestMessage"/>> that will be used to invoke
/// Routes in your lambda function in order to initialize the ASP.NET Core and Lambda pipelines
Expand Down Expand Up @@ -142,7 +141,6 @@ public static IServiceCollection AddAWSLambdaBeforeSnapshotRequest(this IService

return services;
}
#endif

private static bool TryLambdaSetup(IServiceCollection services, LambdaEventSource eventSource, Action<HostingOptions>? configure, out HostingOptions? hostingOptions)
{
Expand Down
Loading
Loading