-
Notifications
You must be signed in to change notification settings - Fork 495
Expand file tree
/
Copy pathLambdaRuntimeSupportServer.cs
More file actions
446 lines (372 loc) · 23.4 KB
/
LambdaRuntimeSupportServer.cs
File metadata and controls
446 lines (372 loc) · 23.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
using System.Diagnostics.CodeAnalysis;
using Amazon.Lambda.AspNetCoreServer.Internal;
using Amazon.Lambda.Core;
using Amazon.Lambda.RuntimeSupport;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Features.Authentication;
using Microsoft.Extensions.DependencyInjection;
namespace Amazon.Lambda.AspNetCoreServer.Hosting.Internal
{
/// <summary>
/// Subclass of Amazon.Lambda.AspNetCoreServer.LambdaServer that also starts
/// up Amazon.Lambda.RuntimeSupport as part of the IServer startup.
///
/// This is an abstract class with subclasses for each of the possible Lambda event sources.
/// </summary>
public abstract class LambdaRuntimeSupportServer : LambdaServer
{
private readonly IServiceProvider _serviceProvider;
internal ILambdaSerializer Serializer;
/// <summary>
/// Creates an instance on the LambdaRuntimeSupportServer
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public LambdaRuntimeSupportServer(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
Serializer = serviceProvider.GetRequiredService<ILambdaSerializer>();
}
/// <summary>
/// Start Amazon.Lambda.RuntimeSupport to listen for Lambda events to be processed.
/// </summary>
/// <typeparam name="TContext"></typeparam>
/// <param name="application"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
public override Task StartAsync<TContext>(IHttpApplication<TContext> application, CancellationToken cancellationToken)
{
base.StartAsync(application, cancellationToken);
var handlerWrapper = CreateHandlerWrapper(_serviceProvider);
var bootStrap = new LambdaBootstrap(handlerWrapper);
return bootStrap.RunAsync();
}
/// <summary>
/// Abstract method that creates the HandlerWrapper that will be invoked for each Lambda event.
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
protected abstract HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider);
}
/// <summary>
/// IServer for handlying Lambda events from an API Gateway HTTP API.
/// </summary>
public class APIGatewayHttpApiV2LambdaRuntimeSupportServer : LambdaRuntimeSupportServer
{
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public APIGatewayHttpApiV2LambdaRuntimeSupportServer(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
/// <summary>
/// Creates HandlerWrapper for processing events from API Gateway HTTP API
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider)
{
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
{
private readonly IEnumerable<GetBeforeSnapshotRequestsCollector> _beforeSnapshotRequestsCollectors;
private readonly HostingOptions? _hostingOptions;
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public APIGatewayHttpApiV2MinimalApi(IServiceProvider serviceProvider)
: base(serviceProvider)
{
_beforeSnapshotRequestsCollectors = serviceProvider.GetServices<GetBeforeSnapshotRequestsCollector>();
// Retrieve HostingOptions from service provider (may be null for backward compatibility)
_hostingOptions = serviceProvider.GetService<HostingOptions>();
// Apply configuration from HostingOptions if available
if (_hostingOptions != null)
{
// Apply binary response configuration
foreach (var kvp in _hostingOptions.ContentTypeEncodings)
{
RegisterResponseContentEncodingForContentType(kvp.Key, kvp.Value);
}
foreach (var kvp in _hostingOptions.ContentEncodingEncodings)
{
RegisterResponseContentEncodingForContentEncoding(kvp.Key, kvp.Value);
}
DefaultResponseContentEncoding = _hostingOptions.DefaultResponseContentEncoding;
// Apply exception handling configuration
IncludeUnhandledExceptionDetailInResponse = _hostingOptions.IncludeUnhandledExceptionDetailInResponse;
}
}
protected override IEnumerable<HttpRequestMessage> GetBeforeSnapshotRequests()
{
foreach (var collector in _beforeSnapshotRequestsCollectors)
if (collector.Request != null)
yield return collector.Request;
}
protected override void PostMarshallRequestFeature(IHttpRequestFeature aspNetCoreRequestFeature, APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallRequestFeature(aspNetCoreRequestFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallRequestFeature?.Invoke(aspNetCoreRequestFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallResponseFeature(IHttpResponseFeature aspNetCoreResponseFeature, APIGatewayEvents.APIGatewayHttpApiV2ProxyResponse lambdaResponse, ILambdaContext lambdaContext)
{
base.PostMarshallResponseFeature(aspNetCoreResponseFeature, lambdaResponse, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallResponseFeature?.Invoke(aspNetCoreResponseFeature, lambdaResponse, lambdaContext);
}
protected override void PostMarshallConnectionFeature(IHttpConnectionFeature aspNetCoreConnectionFeature, APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallConnectionFeature(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallConnectionFeature?.Invoke(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallHttpAuthenticationFeature(IHttpAuthenticationFeature aspNetCoreHttpAuthenticationFeature, APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallHttpAuthenticationFeature(aspNetCoreHttpAuthenticationFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallHttpAuthenticationFeature?.Invoke(aspNetCoreHttpAuthenticationFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallTlsConnectionFeature(ITlsConnectionFeature aspNetCoreConnectionFeature, APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallTlsConnectionFeature(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallTlsConnectionFeature?.Invoke(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallItemsFeatureFeature(IItemsFeature aspNetCoreItemFeature, APIGatewayEvents.APIGatewayHttpApiV2ProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallItemsFeatureFeature(aspNetCoreItemFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
// Note: LAMBDA_CONTEXT and LAMBDA_REQUEST_OBJECT are preserved by the base implementation
_hostingOptions?.PostMarshallItemsFeature?.Invoke(aspNetCoreItemFeature, lambdaRequest, lambdaContext);
}
}
}
/// <summary>
/// IServer for handlying Lambda events from an API Gateway REST API.
/// </summary>
public class APIGatewayRestApiLambdaRuntimeSupportServer : LambdaRuntimeSupportServer
{
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public APIGatewayRestApiLambdaRuntimeSupportServer(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
/// <summary>
/// Creates HandlerWrapper for processing events from API Gateway REST API
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider)
{
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
{
private readonly IEnumerable<GetBeforeSnapshotRequestsCollector> _beforeSnapshotRequestsCollectors;
private readonly HostingOptions? _hostingOptions;
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public APIGatewayRestApiMinimalApi(IServiceProvider serviceProvider)
: base(serviceProvider)
{
_beforeSnapshotRequestsCollectors = serviceProvider.GetServices<GetBeforeSnapshotRequestsCollector>();
// Retrieve HostingOptions from service provider (may be null for backward compatibility)
_hostingOptions = serviceProvider.GetService<HostingOptions>();
// Apply configuration from HostingOptions if available
if (_hostingOptions != null)
{
// Apply binary response configuration
foreach (var kvp in _hostingOptions.ContentTypeEncodings)
{
RegisterResponseContentEncodingForContentType(kvp.Key, kvp.Value);
}
foreach (var kvp in _hostingOptions.ContentEncodingEncodings)
{
RegisterResponseContentEncodingForContentEncoding(kvp.Key, kvp.Value);
}
DefaultResponseContentEncoding = _hostingOptions.DefaultResponseContentEncoding;
// Apply exception handling configuration
IncludeUnhandledExceptionDetailInResponse = _hostingOptions.IncludeUnhandledExceptionDetailInResponse;
}
}
protected override IEnumerable<HttpRequestMessage> GetBeforeSnapshotRequests()
{
foreach (var collector in _beforeSnapshotRequestsCollectors)
if (collector.Request != null)
yield return collector.Request;
}
protected override void PostMarshallRequestFeature(IHttpRequestFeature aspNetCoreRequestFeature, APIGatewayEvents.APIGatewayProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallRequestFeature(aspNetCoreRequestFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallRequestFeature?.Invoke(aspNetCoreRequestFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallResponseFeature(IHttpResponseFeature aspNetCoreResponseFeature, APIGatewayEvents.APIGatewayProxyResponse lambdaResponse, ILambdaContext lambdaContext)
{
base.PostMarshallResponseFeature(aspNetCoreResponseFeature, lambdaResponse, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallResponseFeature?.Invoke(aspNetCoreResponseFeature, lambdaResponse, lambdaContext);
}
protected override void PostMarshallConnectionFeature(IHttpConnectionFeature aspNetCoreConnectionFeature, APIGatewayEvents.APIGatewayProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallConnectionFeature(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallConnectionFeature?.Invoke(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallHttpAuthenticationFeature(IHttpAuthenticationFeature aspNetCoreHttpAuthenticationFeature, APIGatewayEvents.APIGatewayProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallHttpAuthenticationFeature(aspNetCoreHttpAuthenticationFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallHttpAuthenticationFeature?.Invoke(aspNetCoreHttpAuthenticationFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallTlsConnectionFeature(ITlsConnectionFeature aspNetCoreConnectionFeature, APIGatewayEvents.APIGatewayProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallTlsConnectionFeature(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallTlsConnectionFeature?.Invoke(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallItemsFeatureFeature(IItemsFeature aspNetCoreItemFeature, APIGatewayEvents.APIGatewayProxyRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallItemsFeatureFeature(aspNetCoreItemFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
// Note: LAMBDA_CONTEXT and LAMBDA_REQUEST_OBJECT are preserved by the base implementation
_hostingOptions?.PostMarshallItemsFeature?.Invoke(aspNetCoreItemFeature, lambdaRequest, lambdaContext);
}
}
}
/// <summary>
/// IServer for handlying Lambda events from an Application Load Balancer.
/// </summary>
public class ApplicationLoadBalancerLambdaRuntimeSupportServer : LambdaRuntimeSupportServer
{
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public ApplicationLoadBalancerLambdaRuntimeSupportServer(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}
/// <summary>
/// Creates HandlerWrapper for processing events from API Gateway REST API
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
protected override HandlerWrapper CreateHandlerWrapper(IServiceProvider serviceProvider)
{
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
{
private readonly IEnumerable<GetBeforeSnapshotRequestsCollector> _beforeSnapshotRequestsCollectors;
private readonly HostingOptions? _hostingOptions;
/// <summary>
/// Create instances
/// </summary>
/// <param name="serviceProvider">The IServiceProvider created for the ASP.NET Core application</param>
public ApplicationLoadBalancerMinimalApi(IServiceProvider serviceProvider)
: base(serviceProvider)
{
_beforeSnapshotRequestsCollectors = serviceProvider.GetServices<GetBeforeSnapshotRequestsCollector>();
// Retrieve HostingOptions from service provider (may be null for backward compatibility)
_hostingOptions = serviceProvider.GetService<HostingOptions>();
// Apply configuration from HostingOptions if available
if (_hostingOptions != null)
{
// Apply binary response configuration
foreach (var kvp in _hostingOptions.ContentTypeEncodings)
{
RegisterResponseContentEncodingForContentType(kvp.Key, kvp.Value);
}
foreach (var kvp in _hostingOptions.ContentEncodingEncodings)
{
RegisterResponseContentEncodingForContentEncoding(kvp.Key, kvp.Value);
}
DefaultResponseContentEncoding = _hostingOptions.DefaultResponseContentEncoding;
// Apply exception handling configuration
IncludeUnhandledExceptionDetailInResponse = _hostingOptions.IncludeUnhandledExceptionDetailInResponse;
}
}
protected override IEnumerable<HttpRequestMessage> GetBeforeSnapshotRequests()
{
foreach (var collector in _beforeSnapshotRequestsCollectors)
if (collector.Request != null)
yield return collector.Request;
}
protected override void PostMarshallRequestFeature(IHttpRequestFeature aspNetCoreRequestFeature, ApplicationLoadBalancerEvents.ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallRequestFeature(aspNetCoreRequestFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallRequestFeature?.Invoke(aspNetCoreRequestFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallResponseFeature(IHttpResponseFeature aspNetCoreResponseFeature, ApplicationLoadBalancerEvents.ApplicationLoadBalancerResponse lambdaResponse, ILambdaContext lambdaContext)
{
base.PostMarshallResponseFeature(aspNetCoreResponseFeature, lambdaResponse, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallResponseFeature?.Invoke(aspNetCoreResponseFeature, lambdaResponse, lambdaContext);
}
protected override void PostMarshallConnectionFeature(IHttpConnectionFeature aspNetCoreConnectionFeature, ApplicationLoadBalancerEvents.ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallConnectionFeature(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallConnectionFeature?.Invoke(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallHttpAuthenticationFeature(IHttpAuthenticationFeature aspNetCoreHttpAuthenticationFeature, ApplicationLoadBalancerEvents.ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallHttpAuthenticationFeature(aspNetCoreHttpAuthenticationFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallHttpAuthenticationFeature?.Invoke(aspNetCoreHttpAuthenticationFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallTlsConnectionFeature(ITlsConnectionFeature aspNetCoreConnectionFeature, ApplicationLoadBalancerEvents.ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallTlsConnectionFeature(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
_hostingOptions?.PostMarshallTlsConnectionFeature?.Invoke(aspNetCoreConnectionFeature, lambdaRequest, lambdaContext);
}
protected override void PostMarshallItemsFeatureFeature(IItemsFeature aspNetCoreItemFeature, ApplicationLoadBalancerEvents.ApplicationLoadBalancerRequest lambdaRequest, ILambdaContext lambdaContext)
{
base.PostMarshallItemsFeatureFeature(aspNetCoreItemFeature, lambdaRequest, lambdaContext);
// Invoke configured callback if available
// Note: LAMBDA_CONTEXT and LAMBDA_REQUEST_OBJECT are preserved by the base implementation
_hostingOptions?.PostMarshallItemsFeature?.Invoke(aspNetCoreItemFeature, lambdaRequest, lambdaContext);
}
}
}
}