Skip to content

Commit fc98552

Browse files
committed
update AddAWSLambdaBeforeSnapshotRequest() to support AOT by optimizing json serialization, adjust #if blocks and fix simple warnings
1 parent c182df3 commit fc98552

File tree

3 files changed

+88
-52
lines changed

3 files changed

+88
-52
lines changed

Libraries/src/Amazon.Lambda.AspNetCoreServer.Hosting/Internal/LambdaRuntimeSupportServer.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ namespace Amazon.Lambda.AspNetCoreServer.Hosting.Internal
1616
public abstract class LambdaRuntimeSupportServer : LambdaServer
1717
{
1818
private readonly IServiceProvider _serviceProvider;
19+
20+
#if NET8_0_OR_GREATER
1921
private readonly LambdaSnapstartExecuteRequestsBeforeSnapshotHelper _snapstartInitHelper;
22+
#endif
2023

2124
internal ILambdaSerializer Serializer;
2225

@@ -27,7 +30,11 @@ public abstract class LambdaRuntimeSupportServer : LambdaServer
2730
public LambdaRuntimeSupportServer(IServiceProvider serviceProvider)
2831
{
2932
_serviceProvider = serviceProvider;
33+
34+
#if NET8_0_OR_GREATER
3035
_snapstartInitHelper = _serviceProvider.GetRequiredService<LambdaSnapstartExecuteRequestsBeforeSnapshotHelper>();
36+
#endif
37+
3138
Serializer = serviceProvider.GetRequiredService<ILambdaSerializer>();
3239
}
3340

@@ -38,7 +45,6 @@ public LambdaRuntimeSupportServer(IServiceProvider serviceProvider)
3845
/// <param name="application"></param>
3946
/// <param name="cancellationToken"></param>
4047
/// <returns></returns>
41-
[RequiresUnreferencedCode("_snapstartInitHelper Serializes objects to Json")]
4248
public override Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
4349
{
4450
base.StartAsync(application, cancellationToken);

Libraries/src/Amazon.Lambda.AspNetCoreServer.Hosting/Internal/LambdaSnapstartExecuteRequestsBeforeSnapshotHelper.cs

+70-51
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Net;
66
using System.Text;
77
using System.Text.Json;
8+
using System.Text.Json.Serialization;
89
using Amazon.Lambda.APIGatewayEvents;
910
using Amazon.Lambda.ApplicationLoadBalancerEvents;
1011
using Amazon.Lambda.RuntimeSupport;
@@ -14,6 +15,8 @@
1415

1516
namespace Amazon.Lambda.AspNetCoreServer.Hosting.Internal;
1617

18+
#if NET8_0_OR_GREATER
19+
1720
/// <summary>
1821
/// Contains the plumbing to register a user provided <see cref="Func{HttpClient, Task}"/> inside
1922
/// <see cref="Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot"/>.
@@ -22,7 +25,7 @@ namespace Amazon.Lambda.AspNetCoreServer.Hosting.Internal;
2225
/// performance gains offered by SnapStart.
2326
/// <para />
2427
/// It works by construction a specialized <see cref="HttpClient" /> that will intercept requests
25-
/// and saved them inside <see cref="LambdaSnapstartInitializerHttpMessageHandler.CapturedHttpRequests" />.
28+
/// and saved them inside <see cref="LambdaSnapstartInitializerHttpMessageHandler.CapturedHttpRequestsJson" />.
2629
/// <para />
2730
/// Intercepted requests are then be processed later by <see cref="SnapstartHelperLambdaRequests.ExecuteSnapstartInitRequests"/>
2831
/// which will route them correctly through a simulated asp.net/lambda pipeline.
@@ -37,11 +40,8 @@ public LambdaSnapstartExecuteRequestsBeforeSnapshotHelper(LambdaEventSource lamb
3740
}
3841

3942
/// <inheritdoc cref="RegisterInitializerRequests"/>
40-
[RequiresUnreferencedCode("Serializes object to json")]
4143
public void RegisterInitializerRequests(HandlerWrapper handlerWrapper)
4244
{
43-
#if NET8_0_OR_GREATER
44-
4545
Amazon.Lambda.Core.SnapshotRestore.RegisterBeforeSnapshot(async () =>
4646
{
4747
// Construct specialized HttpClient that will intercept requests and saved them inside
@@ -60,39 +60,36 @@ public void RegisterInitializerRequests(HandlerWrapper handlerWrapper)
6060

6161
// Request are now in CapturedHttpRequests. Serialize each one into a json object
6262
// and execute the request through the lambda pipeline (ie handlerWrapper).
63-
foreach (var req in LambdaSnapstartInitializerHttpMessageHandler.CapturedHttpRequests)
63+
foreach (var json in LambdaSnapstartInitializerHttpMessageHandler.CapturedHttpRequestsJson)
6464
{
65-
var json = JsonSerializer.Serialize(req);
66-
6765
await SnapstartHelperLambdaRequests.ExecuteSnapstartInitRequests(json, times: 5, handlerWrapper);
6866
}
6967
});
70-
71-
#endif
7268
}
7369

70+
7471
/// <inheritdoc cref="ServiceCollectionExtensions.AddAWSLambdaBeforeSnapshotRequest"/>
7572
internal static BeforeSnapstartRequestRegistrar Registrar = new();
7673

7774
internal class BeforeSnapstartRequestRegistrar
7875
{
79-
private List<Func<HttpClient, Task>> beforeSnapstartFuncs = new();
76+
private readonly List<Func<HttpClient, Task>> _beforeSnapstartFuncs = new();
8077

8178
public void Register(Func<HttpClient, Task> beforeSnapstartRequest)
8279
{
83-
beforeSnapstartFuncs.Add(beforeSnapstartRequest);
80+
_beforeSnapstartFuncs.Add(beforeSnapstartRequest);
8481
}
8582

8683
internal async Task Execute(HttpClient client)
8784
{
88-
foreach (var f in beforeSnapstartFuncs)
85+
foreach (var f in _beforeSnapstartFuncs)
8986
await f(client);
9087
}
9188
}
9289

9390
private static class SnapstartHelperLambdaRequests
9491
{
95-
private static InternalLogger _logger = InternalLogger.GetDefaultLogger();
92+
private static readonly InternalLogger _logger = InternalLogger.GetDefaultLogger();
9693

9794
private static readonly RuntimeApiHeaders _fakeRuntimeApiHeaders = new(new Dictionary<string, IEnumerable<string>>
9895
{
@@ -136,7 +133,7 @@ private class LambdaSnapstartInitializerHttpMessageHandler : HttpMessageHandler
136133

137134
public static Uri BaseUri { get; } = new Uri("http://localhost");
138135

139-
public static List<object> CapturedHttpRequests { get; } = new();
136+
public static List<string> CapturedHttpRequestsJson { get; } = new();
140137

141138
public LambdaSnapstartInitializerHttpMessageHandler(LambdaEventSource lambdaEventSource)
142139
{
@@ -162,49 +159,60 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
162159
Query = QueryHelpers.ParseNullableQuery(request.RequestUri?.Query)
163160
};
164161

165-
object translatedRequest = _lambdaEventSource switch
162+
string translatedRequestJson = _lambdaEventSource switch
166163
{
167-
LambdaEventSource.ApplicationLoadBalancer => new ApplicationLoadBalancerRequest
168-
{
169-
Body = duckRequest.Body,
170-
Headers = duckRequest.Headers,
171-
Path = duckRequest.Path,
172-
HttpMethod = duckRequest.HttpMethod,
173-
QueryStringParameters = duckRequest.Query?.ToDictionary(k => k.Key, v => v.Value.ToString())
174-
},
175-
LambdaEventSource.HttpApi => new APIGatewayHttpApiV2ProxyRequest
176-
{
177-
Body = duckRequest.Body,
178-
Headers = duckRequest.Headers,
179-
RawPath = duckRequest.Path,
180-
RequestContext = new APIGatewayHttpApiV2ProxyRequest.ProxyRequestContext
181-
{
182-
Http = new APIGatewayHttpApiV2ProxyRequest.HttpDescription
164+
LambdaEventSource.ApplicationLoadBalancer =>
165+
JsonSerializer.Serialize(
166+
new ApplicationLoadBalancerRequest
183167
{
184-
Method = duckRequest.HttpMethod,
185-
Path = duckRequest.Path
186-
}
187-
},
188-
QueryStringParameters = duckRequest.Query?.ToDictionary(k => k.Key, v => v.Value.ToString()),
189-
RawQueryString = duckRequest.RawQuery
190-
},
191-
LambdaEventSource.RestApi => new APIGatewayProxyRequest
192-
{
193-
Body = duckRequest.Body,
194-
Headers = duckRequest.Headers,
195-
Path = duckRequest.Path,
196-
HttpMethod = duckRequest.HttpMethod,
197-
RequestContext = new APIGatewayProxyRequest.ProxyRequestContext
198-
{
199-
HttpMethod = duckRequest.HttpMethod
200-
},
201-
QueryStringParameters = duckRequest.Query?.ToDictionary(k => k.Key, v => v.Value.ToString())
202-
},
168+
Body = duckRequest.Body,
169+
Headers = duckRequest.Headers,
170+
Path = duckRequest.Path,
171+
HttpMethod = duckRequest.HttpMethod,
172+
QueryStringParameters = duckRequest.Query?.ToDictionary(k => k.Key, v => v.Value.ToString())
173+
},
174+
LambdaRequestTypeClasses.Default.ApplicationLoadBalancerRequest),
175+
LambdaEventSource.HttpApi =>
176+
JsonSerializer.Serialize(
177+
new APIGatewayHttpApiV2ProxyRequest
178+
{
179+
Body = duckRequest.Body,
180+
Headers = duckRequest.Headers,
181+
RawPath = duckRequest.Path,
182+
RequestContext = new APIGatewayHttpApiV2ProxyRequest.ProxyRequestContext
183+
{
184+
Http = new APIGatewayHttpApiV2ProxyRequest.HttpDescription
185+
{
186+
Method = duckRequest.HttpMethod,
187+
Path = duckRequest.Path
188+
}
189+
},
190+
QueryStringParameters = duckRequest.Query?.ToDictionary(k => k.Key, v => v.Value.ToString()),
191+
RawQueryString = duckRequest.RawQuery
192+
},
193+
LambdaRequestTypeClasses.Default.APIGatewayHttpApiV2ProxyRequest),
194+
LambdaEventSource.RestApi =>
195+
JsonSerializer.Serialize(
196+
new APIGatewayProxyRequest
197+
{
198+
Body = duckRequest.Body,
199+
Headers = duckRequest.Headers,
200+
Path = duckRequest.Path,
201+
HttpMethod = duckRequest.HttpMethod,
202+
RequestContext = new APIGatewayProxyRequest.ProxyRequestContext
203+
{
204+
HttpMethod = duckRequest.HttpMethod
205+
},
206+
QueryStringParameters = duckRequest.Query?.ToDictionary(k => k.Key, v => v.Value.ToString())
207+
},
208+
LambdaRequestTypeClasses.Default.APIGatewayProxyRequest),
203209
_ => throw new NotImplementedException(
204210
$"Unknown {nameof(LambdaEventSource)}: {Enum.GetName(_lambdaEventSource)}")
205211
};
206212

207-
CapturedHttpRequests.Add(translatedRequest);
213+
// NOTE: Any object added to CapturedHttpRequests must have it's type added
214+
// to the
215+
CapturedHttpRequestsJson.Add(translatedRequestJson);
208216

209217
return new HttpResponseMessage(HttpStatusCode.OK);
210218
}
@@ -218,3 +226,14 @@ private async Task<string> ReadContent(HttpRequestMessage r)
218226
}
219227
}
220228
}
229+
230+
231+
[JsonSourceGenerationOptions(WriteIndented = true)]
232+
[JsonSerializable(typeof(ApplicationLoadBalancerRequest))]
233+
[JsonSerializable(typeof(APIGatewayHttpApiV2ProxyRequest))]
234+
[JsonSerializable(typeof(APIGatewayProxyRequest))]
235+
236+
internal partial class LambdaRequestTypeClasses : JsonSerializerContext
237+
{
238+
}
239+
#endif

Libraries/src/Amazon.Lambda.AspNetCoreServer.Hosting/ServiceCollectionExtensions.cs

+11
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ public static IServiceCollection AddAWSLambdaHosting(this IServiceCollection ser
8888
return services;
8989
}
9090

91+
#if NET8_0_OR_GREATER
9192
/// <summary>
9293
/// Adds a function meant to initialize the asp.net and lambda pipelines during <see cref="SnapshotRestore.RegisterBeforeSnapshot"/>
9394
/// improving the performance gains offered by SnapStart.
@@ -123,9 +124,17 @@ public static IServiceCollection AddAWSLambdaHosting(this IServiceCollection ser
123124
/// ]]>
124125
/// </code>
125126
/// </summary>
127+
#else
128+
/// <summary>
129+
/// Snapstart requires your application to target .NET 8 or above.
130+
/// </summary>
131+
#endif
126132
public static IServiceCollection AddAWSLambdaBeforeSnapshotRequest(this IServiceCollection services, Func<HttpClient, Task> beforeSnapStartRequest)
127133
{
134+
135+
#if NET8_0_OR_GREATER
128136
LambdaSnapstartExecuteRequestsBeforeSnapshotHelper.Registrar.Register(beforeSnapStartRequest);
137+
#endif
129138

130139
return services;
131140
}
@@ -153,8 +162,10 @@ private static bool TryLambdaSetup(IServiceCollection services, LambdaEventSourc
153162

154163
Utilities.EnsureLambdaServerRegistered(services, serverType);
155164

165+
#if NET8_0_OR_GREATER
156166
// register a LambdaSnapStartInitializerHttpMessageHandler
157167
services.AddSingleton<LambdaSnapstartExecuteRequestsBeforeSnapshotHelper>(new LambdaSnapstartExecuteRequestsBeforeSnapshotHelper(eventSource));
168+
#endif
158169

159170
return true;
160171
}

0 commit comments

Comments
 (0)